diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 014c240f11ee7..8daeef0cbd95f 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -26,44 +26,43 @@ pub(super) struct ItemLowerer<'a, 'lowering, 'hir> {
 }
 
 impl ItemLowerer<'_, '_, '_> {
-    fn with_trait_impl_ref(&mut self, impl_ref: &Option<TraitRef>, f: impl FnOnce(&mut Self)) {
+    fn with_trait_impl_ref<T>(
+        &mut self,
+        impl_ref: &Option<TraitRef>,
+        f: impl FnOnce(&mut Self) -> T,
+    ) -> T {
         let old = self.lctx.is_in_trait_impl;
         self.lctx.is_in_trait_impl = impl_ref.is_some();
-        f(self);
+        let ret = f(self);
         self.lctx.is_in_trait_impl = old;
+        ret
     }
 }
 
 impl<'a> Visitor<'a> for ItemLowerer<'a, '_, '_> {
     fn visit_item(&mut self, item: &'a Item) {
-        let mut item_hir_id = None;
-        self.lctx.with_hir_id_owner(item.id, |lctx| {
+        let hir_id = self.lctx.with_hir_id_owner(item.id, |lctx| {
             lctx.without_in_scope_lifetime_defs(|lctx| {
-                if let Some(hir_item) = lctx.lower_item(item) {
-                    let id = lctx.insert_item(hir_item);
-                    item_hir_id = Some(id);
-                }
+                let hir_item = lctx.lower_item(item);
+                lctx.insert_item(hir_item)
             })
         });
 
-        if let Some(hir_id) = item_hir_id {
-            self.lctx.with_parent_item_lifetime_defs(hir_id, |this| {
-                let this = &mut ItemLowerer { lctx: this };
-                match item.kind {
-                    ItemKind::Mod(..) => {
-                        let def_id = this.lctx.lower_node_id(item.id).expect_owner();
-                        let old_current_module =
-                            mem::replace(&mut this.lctx.current_module, def_id);
-                        visit::walk_item(this, item);
-                        this.lctx.current_module = old_current_module;
-                    }
-                    ItemKind::Impl(box ImplKind { ref of_trait, .. }) => {
-                        this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item));
-                    }
-                    _ => visit::walk_item(this, item),
+        self.lctx.with_parent_item_lifetime_defs(hir_id, |this| {
+            let this = &mut ItemLowerer { lctx: this };
+            match item.kind {
+                ItemKind::Mod(..) => {
+                    let def_id = this.lctx.lower_node_id(item.id).expect_owner();
+                    let old_current_module = mem::replace(&mut this.lctx.current_module, def_id);
+                    visit::walk_item(this, item);
+                    this.lctx.current_module = old_current_module;
                 }
-            });
-        }
+                ItemKind::Impl(box ImplKind { ref of_trait, .. }) => {
+                    this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item));
+                }
+                _ => visit::walk_item(this, item),
+            }
+        });
     }
 
     fn visit_fn(&mut self, fk: FnKind<'a>, sp: Span, _: NodeId) {
@@ -113,7 +112,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
     fn with_parent_item_lifetime_defs<T>(
         &mut self,
         parent_hir_id: hir::ItemId,
-        f: impl FnOnce(&mut LoweringContext<'_, '_>) -> T,
+        f: impl FnOnce(&mut Self) -> T,
     ) -> T {
         let old_len = self.in_scope_lifetimes.len();
 
@@ -137,10 +136,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
     // Clears (and restores) the `in_scope_lifetimes` field. Used when
     // visiting nested items, which never inherit in-scope lifetimes
     // from their surrounding environment.
-    fn without_in_scope_lifetime_defs<T>(
-        &mut self,
-        f: impl FnOnce(&mut LoweringContext<'_, '_>) -> T,
-    ) -> T {
+    fn without_in_scope_lifetime_defs<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {
         let old_in_scope_lifetimes = mem::replace(&mut self.in_scope_lifetimes, vec![]);
 
         // this vector is only used when walking over impl headers,
@@ -208,19 +204,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
         }
     }
 
-    pub fn lower_item(&mut self, i: &Item) -> Option<hir::Item<'hir>> {
+    pub fn lower_item(&mut self, i: &Item) -> hir::Item<'hir> {
         let mut ident = i.ident;
         let mut vis = self.lower_visibility(&i.vis, None);
         let hir_id = self.lower_node_id(i.id);
         let attrs = self.lower_attrs(hir_id, &i.attrs);
         let kind = self.lower_item_kind(i.span, i.id, hir_id, &mut ident, attrs, &mut vis, &i.kind);
-        Some(hir::Item {
+        hir::Item {
             def_id: hir_id.expect_owner(),
             ident: self.lower_ident(ident),
             kind,
             vis,
             span: self.lower_span(i.span),
-        })
+        }
     }
 
     fn lower_item_kind(
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 73abd2bb83b9e..a243300edd9d2 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -1442,7 +1442,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 if !self.is_tilde_const_allowed {
                     self.err_handler()
                         .struct_span_err(bound.span(), "`~const` is not allowed here")
-                        .note("only allowed on bounds on traits' associated types, const fns, const impls and its associated functions")
+                        .note("only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions")
                         .emit();
                 }
             }
@@ -1616,7 +1616,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 walk_list!(self, visit_ty, ty);
             }
             AssocItemKind::Fn(box FnKind(_, ref sig, ref generics, ref body))
-                if self.in_const_trait_impl =>
+                if self.in_const_trait_impl || ctxt == AssocCtxt::Trait =>
             {
                 self.visit_vis(&item.vis);
                 self.visit_ident(item.ident);
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 8e2917ee5b47c..346a9e8021731 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -426,6 +426,11 @@ impl<'tcx> Body<'tcx> {
         (arg_count + 1..local_count).map(Local::new)
     }
 
+    #[inline]
+    pub fn drain_vars_and_temps<'a>(&'a mut self) -> impl Iterator<Item = LocalDecl<'tcx>> + 'a {
+        self.local_decls.drain(self.arg_count + 1..)
+    }
+
     /// Changes a statement to a nop. This is both faster than deleting instructions and avoids
     /// invalidating statement indices in `Location`s.
     pub fn make_statement_nop(&mut self, location: Location) {
diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs
index c333667b3ad13..8e9da31eba11f 100644
--- a/compiler/rustc_mir/src/transform/inline.rs
+++ b/compiler/rustc_mir/src/transform/inline.rs
@@ -607,13 +607,7 @@ impl Inliner<'tcx> {
                 }
 
                 // Insert all of the (mapped) parts of the callee body into the caller.
-                caller_body.local_decls.extend(
-                    // FIXME(eddyb) make `Range<Local>` iterable so that we can use
-                    // `callee_body.local_decls.drain(callee_body.vars_and_temps())`
-                    callee_body
-                        .vars_and_temps_iter()
-                        .map(|local| callee_body.local_decls[local].clone()),
-                );
+                caller_body.local_decls.extend(callee_body.drain_vars_and_temps());
                 caller_body.source_scopes.extend(&mut callee_body.source_scopes.drain(..));
                 caller_body.var_debug_info.append(&mut callee_body.var_debug_info);
                 caller_body.basic_blocks_mut().extend(callee_body.basic_blocks_mut().drain(..));
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 89e032b222fec..10e9bde0d972b 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -597,6 +597,14 @@ impl Span {
         if !expn_data.is_root() { Some(expn_data.call_site) } else { None }
     }
 
+    /// Walk down the expansion ancestors to find a span that's contained within `outer`.
+    pub fn find_ancestor_inside(mut self, outer: Span) -> Option<Span> {
+        while !outer.contains(self) {
+            self = self.parent()?;
+        }
+        Some(self)
+    }
+
     /// Edition of the crate from which this span came.
     pub fn edition(self) -> edition::Edition {
         self.ctxt().edition()
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 911956859b861..4d0cad80764e9 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1501,7 +1501,8 @@ impl Target {
             | Cdecl
             | EfiApi => true,
             X86Interrupt => ["x86", "x86_64"].contains(&&self.arch[..]),
-            Aapcs | CCmseNonSecureCall => ["arm", "aarch64"].contains(&&self.arch[..]),
+            Aapcs => "arm" == self.arch,
+            CCmseNonSecureCall => ["arm", "aarch64"].contains(&&self.arch[..]),
             Win64 | SysV64 => self.arch == "x86_64",
             PtxKernel => self.arch == "nvptx64",
             Msp430Interrupt => self.arch == "msp430",
diff --git a/compiler/rustc_typeck/src/check/method/prelude2021.rs b/compiler/rustc_typeck/src/check/method/prelude2021.rs
index 1347f56258ea1..5c8056b244242 100644
--- a/compiler/rustc_typeck/src/check/method/prelude2021.rs
+++ b/compiler/rustc_typeck/src/check/method/prelude2021.rs
@@ -156,15 +156,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         segment.ident.name
                     ));
 
-                    let (self_adjusted, precise) = self.adjust_expr(pick, self_expr);
+                    let (self_adjusted, precise) = self.adjust_expr(pick, self_expr, sp);
                     if precise {
                         let args = args
                             .iter()
                             .skip(1)
                             .map(|arg| {
+                                let span = arg.span.find_ancestor_inside(sp).unwrap_or_default();
                                 format!(
                                     ", {}",
-                                    self.sess().source_map().span_to_snippet(arg.span).unwrap()
+                                    self.sess().source_map().span_to_snippet(span).unwrap()
                                 )
                             })
                             .collect::<String>();
@@ -173,8 +174,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             sp,
                             "disambiguate the associated function",
                             format!(
-                                "{}::{}({}{})",
-                                trait_name, segment.ident.name, self_adjusted, args
+                                "{}::{}{}({}{})",
+                                trait_name,
+                                segment.ident.name,
+                                if let Some(args) = segment.args.as_ref().and_then(|args| self
+                                    .sess()
+                                    .source_map()
+                                    .span_to_snippet(args.span_ext)
+                                    .ok())
+                                {
+                                    // Keep turbofish.
+                                    format!("::{}", args)
+                                } else {
+                                    String::new()
+                                },
+                                self_adjusted,
+                                args,
                             ),
                             Applicability::MachineApplicable,
                         );
@@ -272,11 +287,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 method_name.name
             ));
 
-            let mut self_ty_name = self
-                .sess()
-                .source_map()
-                .span_to_snippet(self_ty_span)
-                .unwrap_or_else(|_| self_ty.to_string());
+            let mut self_ty_name = self_ty_span
+                .find_ancestor_inside(span)
+                .and_then(|span| self.sess().source_map().span_to_snippet(span).ok())
+                .unwrap_or_else(|| self_ty.to_string());
 
             // Get the number of generics the self type has (if an Adt) unless we can determine that
             // the user has written the self type with generics already which we (naively) do by looking
@@ -370,7 +384,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Creates a string version of the `expr` that includes explicit adjustments.
     /// Returns the string and also a bool indicating whther this is a *precise*
     /// suggestion.
-    fn adjust_expr(&self, pick: &Pick<'tcx>, expr: &hir::Expr<'tcx>) -> (String, bool) {
+    fn adjust_expr(
+        &self,
+        pick: &Pick<'tcx>,
+        expr: &hir::Expr<'tcx>,
+        outer: Span,
+    ) -> (String, bool) {
         let derefs = "*".repeat(pick.autoderefs);
 
         let autoref = match pick.autoref_or_ptr_adjustment {
@@ -379,12 +398,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "",
         };
 
-        let (expr_text, precise) =
-            if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) {
-                (expr_text, true)
-            } else {
-                ("(..)".to_string(), false)
-            };
+        let (expr_text, precise) = if let Some(expr_text) = expr
+            .span
+            .find_ancestor_inside(outer)
+            .and_then(|span| self.sess().source_map().span_to_snippet(span).ok())
+        {
+            (expr_text, true)
+        } else {
+            ("(..)".to_string(), false)
+        };
 
         let adjusted_text = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) =
             pick.autoref_or_ptr_adjustment
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs
index 75fd545060c4a..a25d0f8064404 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_typeck/src/check/upvar.rs
@@ -680,15 +680,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         migrated_variables_concat
                     );
 
-                    let mut closure_body_span = self.tcx.hir().span(body_id.hir_id);
-
                     // If the body was entirely expanded from a macro
                     // invocation, i.e. the body is not contained inside the
                     // closure span, then we walk up the expansion until we
                     // find the span before the expansion.
-                    while !closure_body_span.is_dummy() && !closure_span.contains(closure_body_span) {
-                        closure_body_span = closure_body_span.parent().unwrap_or(DUMMY_SP);
-                    }
+                    let closure_body_span = self.tcx.hir().span(body_id.hir_id)
+                        .find_ancestor_inside(closure_span)
+                        .unwrap_or(DUMMY_SP);
 
                     if let Ok(s) = self.tcx.sess.source_map().span_to_snippet(closure_body_span) {
                         let mut lines = s.lines();
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 1a6d1aed2fd1e..d667fff4b81ee 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -76,6 +76,7 @@
 #![feature(const_alloc_layout)]
 #![feature(const_arguments_as_str)]
 #![feature(const_assert_type)]
+#![feature(const_bigint_helper_methods)]
 #![feature(const_caller_location)]
 #![feature(const_cell_into_inner)]
 #![feature(const_discriminant)]
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index 2c866812937e9..1a310917fdfc4 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -1341,6 +1341,33 @@ macro_rules! int_impl {
             (a as Self, b)
         }
 
+        /// Calculates `self + rhs + carry` without the ability to overflow.
+        ///
+        /// Performs "ternary addition" which takes in an extra bit to add, and may return an
+        /// additional bit of overflow. This allows for chaining together multiple additions
+        /// to create "big integers" which represent larger values.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage
+        ///
+        /// ```
+        /// #![feature(bigint_helper_methods)]
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, false), (7, false));")]
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, true), (8, false));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, false), (", stringify!($SelfT), "::MIN, false));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, true), (", stringify!($SelfT), "::MIN + 1, false));")]
+        /// ```
+        #[unstable(feature = "bigint_helper_methods", issue = "85532")]
+        #[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn carrying_add(self, rhs: Self, carry: bool) -> (Self, bool) {
+            let (sum, carry) = (self as $UnsignedT).carrying_add(rhs as $UnsignedT, carry);
+            (sum as $SelfT, carry)
+        }
+
         /// Calculates `self` - `rhs`
         ///
         /// Returns a tuple of the subtraction along with a boolean indicating whether an arithmetic overflow
@@ -1365,6 +1392,33 @@ macro_rules! int_impl {
             (a as Self, b)
         }
 
+        /// Calculates `self - rhs - borrow` without the ability to overflow.
+        ///
+        /// Performs "ternary subtraction" which takes in an extra bit to subtract, and may return
+        /// an additional bit of overflow. This allows for chaining together multiple subtractions
+        /// to create "big integers" which represent larger values.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage
+        ///
+        /// ```
+        /// #![feature(bigint_helper_methods)]
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".borrowing_sub(2, false), (3, false));")]
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".borrowing_sub(2, true), (2, false));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.borrowing_sub(1, false), (", stringify!($SelfT), "::MAX, false));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.borrowing_sub(1, true), (", stringify!($SelfT), "::MAX - 1, false));")]
+        /// ```
+        #[unstable(feature = "bigint_helper_methods", issue = "85532")]
+        #[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn borrowing_sub(self, rhs: Self, borrow: bool) -> (Self, bool) {
+            let (sum, borrow) = (self as $UnsignedT).borrowing_sub(rhs as $UnsignedT, borrow);
+            (sum as $SelfT, borrow)
+        }
+
         /// Calculates the multiplication of `self` and `rhs`.
         ///
         /// Returns a tuple of the multiplication along with a boolean indicating whether an arithmetic overflow
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index 09b7418bec0d9..59b68cbe9c0ce 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -93,20 +93,96 @@ depending on the target pointer size.
     };
 }
 
+macro_rules! widening_impl {
+    ($SelfT:ty, $WideT:ty, $BITS:literal) => {
+        /// Calculates the complete product `self * rhs` without the possibility to overflow.
+        ///
+        /// This returns the low-order (wrapping) bits and the high-order (overflow) bits
+        /// of the result as two separate values, in that order.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// Please note that this example is shared between integer types.
+        /// Which explains why `u32` is used here.
+        ///
+        /// ```
+        /// #![feature(bigint_helper_methods)]
+        /// assert_eq!(5u32.widening_mul(2), (10, 0));
+        /// assert_eq!(1_000_000_000u32.widening_mul(10), (1410065408, 2));
+        /// ```
+        #[unstable(feature = "bigint_helper_methods", issue = "85532")]
+        #[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn widening_mul(self, rhs: Self) -> (Self, Self) {
+            // note: longer-term this should be done via an intrinsic,
+            //   but for now we can deal without an impl for u128/i128
+            // SAFETY: overflow will be contained within the wider types
+            let wide = unsafe { (self as $WideT).unchecked_mul(rhs as $WideT) };
+            (wide as $SelfT, (wide >> $BITS) as $SelfT)
+        }
+
+        /// Calculates the "full multiplication" `self * rhs + carry`
+        /// without the possibility to overflow.
+        ///
+        /// This returns the low-order (wrapping) bits and the high-order (overflow) bits
+        /// of the result as two separate values, in that order.
+        ///
+        /// Performs "long multiplication" which takes in an extra amount to add, and may return an
+        /// additional amount of overflow. This allows for chaining together multiple
+        /// multiplications to create "big integers" which represent larger values.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// Please note that this example is shared between integer types.
+        /// Which explains why `u32` is used here.
+        ///
+        /// ```
+        /// #![feature(bigint_helper_methods)]
+        /// assert_eq!(5u32.carrying_mul(2, 0), (10, 0));
+        /// assert_eq!(5u32.carrying_mul(2, 10), (20, 0));
+        /// assert_eq!(1_000_000_000u32.carrying_mul(10, 0), (1410065408, 2));
+        /// assert_eq!(1_000_000_000u32.carrying_mul(10, 10), (1410065418, 2));
+        /// ```
+        #[unstable(feature = "bigint_helper_methods", issue = "85532")]
+        #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn carrying_mul(self, rhs: Self, carry: Self) -> (Self, Self) {
+            // note: longer-term this should be done via an intrinsic,
+            //   but for now we can deal without an impl for u128/i128
+            // SAFETY: overflow will be contained within the wider types
+            let wide = unsafe {
+                (self as $WideT).unchecked_mul(rhs as $WideT).unchecked_add(carry as $WideT)
+            };
+            (wide as $SelfT, (wide >> $BITS) as $SelfT)
+        }
+    };
+}
+
 #[lang = "i8"]
 impl i8 {
+    widening_impl! { i8, i16, 8 }
     int_impl! { i8, i8, u8, 8, 7, -128, 127, 2, "-0x7e", "0xa", "0x12", "0x12", "0x48",
     "[0x12]", "[0x12]", "", "" }
 }
 
 #[lang = "i16"]
 impl i16 {
+    widening_impl! { i16, i32, 16 }
     int_impl! { i16, i16, u16, 16, 15, -32768, 32767, 4, "-0x5ffd", "0x3a", "0x1234", "0x3412",
     "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", "", "" }
 }
 
 #[lang = "i32"]
 impl i32 {
+    widening_impl! { i32, i64, 32 }
     int_impl! { i32, i32, u32, 32, 31, -2147483648, 2147483647, 8, "0x10000b3", "0xb301",
     "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]",
     "[0x12, 0x34, 0x56, 0x78]", "", "" }
@@ -114,6 +190,7 @@ impl i32 {
 
 #[lang = "i64"]
 impl i64 {
+    widening_impl! { i64, i128, 64 }
     int_impl! { i64, i64, u64, 64, 63, -9223372036854775808, 9223372036854775807, 12,
     "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412",
     "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
@@ -135,6 +212,7 @@ impl i128 {
 #[cfg(target_pointer_width = "16")]
 #[lang = "isize"]
 impl isize {
+    widening_impl! { isize, i32, 16 }
     int_impl! { isize, i16, usize, 16, 15, -32768, 32767, 4, "-0x5ffd", "0x3a", "0x1234",
     "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]",
     usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
@@ -143,6 +221,7 @@ impl isize {
 #[cfg(target_pointer_width = "32")]
 #[lang = "isize"]
 impl isize {
+    widening_impl! { isize, i64, 32 }
     int_impl! { isize, i32, usize, 32, 31, -2147483648, 2147483647, 8, "0x10000b3", "0xb301",
     "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]",
     "[0x12, 0x34, 0x56, 0x78]",
@@ -152,6 +231,7 @@ impl isize {
 #[cfg(target_pointer_width = "64")]
 #[lang = "isize"]
 impl isize {
+    widening_impl! { isize, i128, 64 }
     int_impl! { isize, i64, usize, 64, 63, -9223372036854775808, 9223372036854775807,
     12, "0xaa00000000006e1", "0x6e10aa",  "0x1234567890123456", "0x5634129078563412",
      "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
@@ -164,6 +244,7 @@ const ASCII_CASE_MASK: u8 = 0b0010_0000;
 
 #[lang = "u8"]
 impl u8 {
+    widening_impl! { u8, u16, 8 }
     uint_impl! { u8, u8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]",
     "[0x12]", "", "" }
 
@@ -697,18 +778,21 @@ impl u8 {
 
 #[lang = "u16"]
 impl u16 {
+    widening_impl! { u16, u32, 16 }
     uint_impl! { u16, u16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
     "[0x34, 0x12]", "[0x12, 0x34]", "", "" }
 }
 
 #[lang = "u32"]
 impl u32 {
+    widening_impl! { u32, u64, 32 }
     uint_impl! { u32, u32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
     "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", "", "" }
 }
 
 #[lang = "u64"]
 impl u64 {
+    widening_impl! { u64, u128, 64 }
     uint_impl! { u64, u64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
     "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48",
     "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
@@ -731,6 +815,7 @@ impl u128 {
 #[cfg(target_pointer_width = "16")]
 #[lang = "usize"]
 impl usize {
+    widening_impl! { usize, u32, 16 }
     uint_impl! { usize, u16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
     "[0x34, 0x12]", "[0x12, 0x34]",
     usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
@@ -738,6 +823,7 @@ impl usize {
 #[cfg(target_pointer_width = "32")]
 #[lang = "usize"]
 impl usize {
+    widening_impl! { usize, u64, 32 }
     uint_impl! { usize, u32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
     "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]",
     usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
@@ -746,6 +832,7 @@ impl usize {
 #[cfg(target_pointer_width = "64")]
 #[lang = "usize"]
 impl usize {
+    widening_impl! { usize, u128, 64 }
     uint_impl! { usize, u64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
     "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48",
     "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index d6bd3115a0254..9366efb32bcf9 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -1408,6 +1408,36 @@ macro_rules! uint_impl {
             (a as Self, b)
         }
 
+        /// Calculates `self + rhs + carry` without the ability to overflow.
+        ///
+        /// Performs "ternary addition" which takes in an extra bit to add, and may return an
+        /// additional bit of overflow. This allows for chaining together multiple additions
+        /// to create "big integers" which represent larger values.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage
+        ///
+        /// ```
+        /// #![feature(bigint_helper_methods)]
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, false), (7, false));")]
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, true), (8, false));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, false), (0, true));")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, true), (1, true));")]
+        /// ```
+        #[unstable(feature = "bigint_helper_methods", issue = "85532")]
+        #[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn carrying_add(self, rhs: Self, carry: bool) -> (Self, bool) {
+            // note: longer-term this should be done via an intrinsic, but this has been shown
+            //   to generate optimal code for now, and LLVM doesn't have an equivalent intrinsic
+            let (a, b) = self.overflowing_add(rhs);
+            let (c, d) = a.overflowing_add(carry as $SelfT);
+            (c, b | d)
+        }
+
         /// Calculates `self` - `rhs`
         ///
         /// Returns a tuple of the subtraction along with a boolean indicating
@@ -1433,6 +1463,36 @@ macro_rules! uint_impl {
             (a as Self, b)
         }
 
+        /// Calculates `self - rhs - borrow` without the ability to overflow.
+        ///
+        /// Performs "ternary subtraction" which takes in an extra bit to subtract, and may return
+        /// an additional bit of overflow. This allows for chaining together multiple subtractions
+        /// to create "big integers" which represent larger values.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage
+        ///
+        /// ```
+        /// #![feature(bigint_helper_methods)]
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".borrowing_sub(2, false), (3, false));")]
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".borrowing_sub(2, true), (2, false));")]
+        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".borrowing_sub(1, false), (", stringify!($SelfT), "::MAX, true));")]
+        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".borrowing_sub(1, true), (", stringify!($SelfT), "::MAX - 1, true));")]
+        /// ```
+        #[unstable(feature = "bigint_helper_methods", issue = "85532")]
+        #[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn borrowing_sub(self, rhs: Self, borrow: bool) -> (Self, bool) {
+            // note: longer-term this should be done via an intrinsic, but this has been shown
+            //   to generate optimal code for now, and LLVM doesn't have an equivalent intrinsic
+            let (a, b) = self.overflowing_sub(rhs);
+            let (c, d) = a.overflowing_sub(borrow as $SelfT);
+            (c, b | d)
+        }
+
         /// Calculates the multiplication of `self` and `rhs`.
         ///
         /// Returns a tuple of the multiplication along with a boolean
diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs
index 336891ec1eb94..5b4a9fa7979de 100644
--- a/library/std/src/net/tcp.rs
+++ b/library/std/src/net/tcp.rs
@@ -401,6 +401,53 @@ impl TcpStream {
         self.0.peek(buf)
     }
 
+    /// Sets the value of the `SO_LINGER` option on this socket.
+    ///
+    /// This value controls how the socket is closed when data remains
+    /// to be sent. If `SO_LINGER` is set, the socket will remain open
+    /// for the specified duration as the system attempts to send pending data.
+    /// Otherwise, the system may close the socket immediately, or wait for a
+    /// default timeout.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(tcp_linger)]
+    ///
+    /// use std::net::TcpStream;
+    /// use std::time::Duration;
+    ///
+    /// let stream = TcpStream::connect("127.0.0.1:8080")
+    ///                        .expect("Couldn't connect to the server...");
+    /// stream.set_linger(Some(Duration::from_secs(0))).expect("set_linger call failed");
+    /// ```
+    #[unstable(feature = "tcp_linger", issue = "88494")]
+    pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
+        self.0.set_linger(linger)
+    }
+
+    /// Gets the value of the `SO_LINGER` option on this socket.
+    ///
+    /// For more information about this option, see [`TcpStream::set_linger`].
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// #![feature(tcp_linger)]
+    ///
+    /// use std::net::TcpStream;
+    /// use std::time::Duration;
+    ///
+    /// let stream = TcpStream::connect("127.0.0.1:8080")
+    ///                        .expect("Couldn't connect to the server...");
+    /// stream.set_linger(Some(Duration::from_secs(0))).expect("set_linger call failed");
+    /// assert_eq!(stream.linger().unwrap(), Some(Duration::from_secs(0)));
+    /// ```
+    #[unstable(feature = "tcp_linger", issue = "88494")]
+    pub fn linger(&self) -> io::Result<Option<Duration>> {
+        self.0.linger()
+    }
+
     /// Sets the value of the `TCP_NODELAY` option on this socket.
     ///
     /// If set, this option disables the Nagle algorithm. This means that
diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs
index 387a3617e5e9a..c2061c1351262 100644
--- a/library/std/src/net/tcp/tests.rs
+++ b/library/std/src/net/tcp/tests.rs
@@ -767,6 +767,21 @@ fn test_timeout_zero_duration() {
     drop(listener);
 }
 
+#[test]
+#[cfg_attr(target_env = "sgx", ignore)]
+fn linger() {
+    let addr = next_test_ip4();
+    let _listener = t!(TcpListener::bind(&addr));
+
+    let stream = t!(TcpStream::connect(&("localhost", addr.port())));
+
+    assert_eq!(None, t!(stream.linger()));
+    t!(stream.set_linger(Some(Duration::from_secs(1))));
+    assert_eq!(Some(Duration::from_secs(1)), t!(stream.linger()));
+    t!(stream.set_linger(None));
+    assert_eq!(None, t!(stream.linger()));
+}
+
 #[test]
 #[cfg_attr(target_env = "sgx", ignore)]
 fn nodelay() {
diff --git a/library/std/src/net/udp.rs b/library/std/src/net/udp.rs
index 871505843af23..6354752e64e76 100644
--- a/library/std/src/net/udp.rs
+++ b/library/std/src/net/udp.rs
@@ -39,7 +39,7 @@ use crate::time::Duration;
 ///
 /// fn main() -> std::io::Result<()> {
 ///     {
-///         let mut socket = UdpSocket::bind("127.0.0.1:34254")?;
+///         let socket = UdpSocket::bind("127.0.0.1:34254")?;
 ///
 ///         // Receives a single datagram message on the socket. If `buf` is too small to hold
 ///         // the message, it will be cut off.
diff --git a/library/std/src/sys/hermit/net.rs b/library/std/src/sys/hermit/net.rs
index 3f0c99cf74289..880ef678a4f7a 100644
--- a/library/std/src/sys/hermit/net.rs
+++ b/library/std/src/sys/hermit/net.rs
@@ -182,6 +182,14 @@ impl TcpStream {
         Ok(self.clone())
     }
 
+    pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
+        unsupported()
+    }
+
+    pub fn linger(&self) -> io::Result<Option<Duration>> {
+        unsupported()
+    }
+
     pub fn set_nodelay(&self, mode: bool) -> io::Result<()> {
         abi::tcpstream::set_nodelay(*self.0.as_inner(), mode)
             .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"set_nodelay failed"))
diff --git a/library/std/src/sys/sgx/net.rs b/library/std/src/sys/sgx/net.rs
index 3a69aa039ef2e..89c5af6124f20 100644
--- a/library/std/src/sys/sgx/net.rs
+++ b/library/std/src/sys/sgx/net.rs
@@ -183,6 +183,14 @@ impl TcpStream {
         Ok(self.clone())
     }
 
+    pub fn set_linger(&self, _: Option<Duration>) -> io::Result<()> {
+        sgx_ineffective(())
+    }
+
+    pub fn linger(&self) -> io::Result<Option<Duration>> {
+        sgx_ineffective(None)
+    }
+
     pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
         sgx_ineffective(())
     }
diff --git a/library/std/src/sys/unix/l4re.rs b/library/std/src/sys/unix/l4re.rs
index 3cf637c82285a..ba63b41534c1a 100644
--- a/library/std/src/sys/unix/l4re.rs
+++ b/library/std/src/sys/unix/l4re.rs
@@ -98,6 +98,14 @@ pub mod net {
             unimpl!();
         }
 
+        pub fn set_linger(&self, _: Option<Duration>) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn linger(&self) -> io::Result<Option<Duration>> {
+            unimpl!();
+        }
+
         pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
             unimpl!();
         }
@@ -214,6 +222,14 @@ pub mod net {
             unimpl!();
         }
 
+        pub fn set_linger(&self, _: Option<Duration>) -> io::Result<()> {
+            unimpl!();
+        }
+
+        pub fn linger(&self) -> io::Result<Option<Duration>> {
+            unimpl!();
+        }
+
         pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
             unimpl!();
         }
diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs
index c2f5da1dbbb11..9ae6d12dcb95c 100644
--- a/library/std/src/sys/unix/net.rs
+++ b/library/std/src/sys/unix/net.rs
@@ -12,6 +12,14 @@ use crate::time::{Duration, Instant};
 
 use libc::{c_int, c_void, size_t, sockaddr, socklen_t, MSG_PEEK};
 
+cfg_if::cfg_if! {
+    if #[cfg(target_vendor = "apple")] {
+        use libc::SO_LINGER_SEC as SO_LINGER;
+    } else {
+        use libc::SO_LINGER;
+    }
+}
+
 pub use crate::sys::{cvt, cvt_r};
 
 #[allow(unused_extern_crates)]
@@ -376,6 +384,21 @@ impl Socket {
         Ok(())
     }
 
+    pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
+        let linger = libc::linger {
+            l_onoff: linger.is_some() as libc::c_int,
+            l_linger: linger.unwrap_or_default().as_secs() as libc::c_int,
+        };
+
+        setsockopt(self, libc::SOL_SOCKET, SO_LINGER, linger)
+    }
+
+    pub fn linger(&self) -> io::Result<Option<Duration>> {
+        let val: libc::linger = getsockopt(self, libc::SOL_SOCKET, SO_LINGER)?;
+
+        Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64)))
+    }
+
     pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
         setsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int)
     }
diff --git a/library/std/src/sys/unsupported/net.rs b/library/std/src/sys/unsupported/net.rs
index 96203c74b576c..dbb6ce22c22de 100644
--- a/library/std/src/sys/unsupported/net.rs
+++ b/library/std/src/sys/unsupported/net.rs
@@ -76,6 +76,14 @@ impl TcpStream {
         self.0
     }
 
+    pub fn set_linger(&self, _: Option<Duration>) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn linger(&self) -> io::Result<Option<Duration>> {
+        self.0
+    }
+
     pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
         self.0
     }
diff --git a/library/std/src/sys/wasi/net.rs b/library/std/src/sys/wasi/net.rs
index c7c4a9f6efdfb..a4dbb225376ee 100644
--- a/library/std/src/sys/wasi/net.rs
+++ b/library/std/src/sys/wasi/net.rs
@@ -127,6 +127,14 @@ impl TcpStream {
         unsupported()
     }
 
+    pub fn set_linger(&self, _: Option<Duration>) -> io::Result<()> {
+        unsupported()
+    }
+
+    pub fn linger(&self) -> io::Result<Option<Duration>> {
+        unsupported()
+    }
+
     pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
         unsupported()
     }
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index 63f9be7b7e350..cedf389fbf503 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -197,6 +197,7 @@ pub const SOCK_DGRAM: c_int = 2;
 pub const SOCK_STREAM: c_int = 1;
 pub const SOCKET_ERROR: c_int = -1;
 pub const SOL_SOCKET: c_int = 0xffff;
+pub const SO_LINGER: c_int = 0x0080;
 pub const SO_RCVTIMEO: c_int = 0x1006;
 pub const SO_SNDTIMEO: c_int = 0x1005;
 pub const IPPROTO_IP: c_int = 0;
@@ -216,6 +217,13 @@ pub const IPV6_ADD_MEMBERSHIP: c_int = 12;
 pub const IPV6_DROP_MEMBERSHIP: c_int = 13;
 pub const MSG_PEEK: c_int = 0x2;
 
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct linger {
+    pub l_onoff: c_ushort,
+    pub l_linger: c_ushort,
+}
+
 #[repr(C)]
 pub struct ip_mreq {
     pub imr_multiaddr: in_addr,
diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs
index 55aacb38c6f78..33152cc97abc0 100644
--- a/library/std/src/sys/windows/net.rs
+++ b/library/std/src/sys/windows/net.rs
@@ -15,7 +15,7 @@ use crate::sys_common::net;
 use crate::sys_common::{AsInner, FromInner, IntoInner};
 use crate::time::Duration;
 
-use libc::{c_int, c_long, c_ulong};
+use libc::{c_int, c_long, c_ulong, c_ushort};
 
 pub type wrlen_t = i32;
 
@@ -446,6 +446,21 @@ impl Socket {
         cvt(result).map(drop)
     }
 
+    pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
+        let linger = c::linger {
+            l_onoff: linger.is_some() as c_ushort,
+            l_linger: linger.unwrap_or_default().as_secs() as c_ushort,
+        };
+
+        net::setsockopt(self, c::SOL_SOCKET, c::SO_LINGER, linger)
+    }
+
+    pub fn linger(&self) -> io::Result<Option<Duration>> {
+        let val: c::linger = net::getsockopt(self, c::SOL_SOCKET, c::SO_LINGER)?;
+
+        Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64)))
+    }
+
     pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
         net::setsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY, nodelay as c::BYTE)
     }
diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs
index 0ffa5c01dd33b..c5c3df361f34b 100644
--- a/library/std/src/sys_common/net.rs
+++ b/library/std/src/sys_common/net.rs
@@ -297,6 +297,14 @@ impl TcpStream {
         self.inner.duplicate().map(|s| TcpStream { inner: s })
     }
 
+    pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
+        self.inner.set_linger(linger)
+    }
+
+    pub fn linger(&self) -> io::Result<Option<Duration>> {
+        self.inner.linger()
+    }
+
     pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
         self.inner.set_nodelay(nodelay)
     }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 640acffb114d9..b566239423e04 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1702,12 +1702,28 @@ impl Clean<VariantStruct> for rustc_hir::VariantData<'_> {
     }
 }
 
+impl Clean<Vec<Item>> for hir::VariantData<'_> {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Vec<Item> {
+        self.fields().iter().map(|x| x.clean(cx)).collect()
+    }
+}
+
 impl Clean<Item> for ty::VariantDef {
     fn clean(&self, cx: &mut DocContext<'_>) -> Item {
         let kind = match self.ctor_kind {
             CtorKind::Const => Variant::CLike,
             CtorKind::Fn => Variant::Tuple(
-                self.fields.iter().map(|f| cx.tcx.type_of(f.did).clean(cx)).collect(),
+                self.fields
+                    .iter()
+                    .map(|field| {
+                        let name = Some(field.ident.name);
+                        let kind = StructFieldItem(cx.tcx.type_of(field.did).clean(cx));
+                        let what_rustc_thinks =
+                            Item::from_def_id_and_parts(field.did, name, kind, cx);
+                        // don't show `pub` for fields, which are always public
+                        Item { visibility: Visibility::Inherited, ..what_rustc_thinks }
+                    })
+                    .collect(),
             ),
             CtorKind::Fictive => Variant::Struct(VariantStruct {
                 struct_type: CtorKind::Fictive,
@@ -1737,13 +1753,7 @@ impl Clean<Variant> for hir::VariantData<'_> {
     fn clean(&self, cx: &mut DocContext<'_>) -> Variant {
         match self {
             hir::VariantData::Struct(..) => Variant::Struct(self.clean(cx)),
-            // Important note here: `Variant::Tuple` is used on tuple structs which are not in an
-            // enum (so where converting from `ty::VariantDef`). In case we are in an enum, the kind
-            // is provided by the `Variant` wrapper directly, and since we need the fields' name
-            // (even for a tuple struct variant!), it's simpler to just store it as a
-            // `Variant::Struct` instead of a `Variant::Tuple` (otherwise it would force us to make
-            // a lot of changes when rendering them to generate the name as well).
-            hir::VariantData::Tuple(..) => Variant::Struct(self.clean(cx)),
+            hir::VariantData::Tuple(..) => Variant::Tuple(self.clean(cx)),
             hir::VariantData::Unit(..) => Variant::CLike,
         }
     }
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 7025574914331..4194c99c0ba70 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -715,6 +715,7 @@ impl ItemKind {
             StructItem(s) => s.fields.iter(),
             UnionItem(u) => u.fields.iter(),
             VariantItem(Variant::Struct(v)) => v.fields.iter(),
+            VariantItem(Variant::Tuple(v)) => v.iter(),
             EnumItem(e) => e.variants.iter(),
             TraitItem(t) => t.items.iter(),
             ImplItem(i) => i.items.iter(),
@@ -1937,7 +1938,7 @@ crate struct Enum {
 #[derive(Clone, Debug)]
 crate enum Variant {
     CLike,
-    Tuple(Vec<Type>),
+    Tuple(Vec<Item>),
     Struct(VariantStruct),
 }
 
diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs
index 45aae71d2dc57..b4859e4c9c7fe 100644
--- a/src/librustdoc/fold.rs
+++ b/src/librustdoc/fold.rs
@@ -56,6 +56,10 @@ crate trait DocFolder: Sized {
                             || j.fields.iter().any(|f| f.is_stripped());
                         VariantItem(Variant::Struct(j))
                     }
+                    Variant::Tuple(fields) => {
+                        let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
+                        VariantItem(Variant::Tuple(fields))
+                    }
                     _ => VariantItem(i2),
                 }
             }
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 8f4857a693928..722cfc97a8d89 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -937,6 +937,19 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni
     document_type_layout(w, cx, def_id);
 }
 
+fn print_tuple_struct_fields(w: &mut Buffer, cx: &Context<'_>, s: &[clean::Item]) {
+    for (i, ty) in s
+        .iter()
+        .map(|f| if let clean::StructFieldItem(ref ty) = *f.kind { ty } else { unreachable!() })
+        .enumerate()
+    {
+        if i > 0 {
+            w.write_str(",&nbsp;");
+        }
+        write!(w, "{}", ty.print(cx));
+    }
+}
+
 fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum) {
     wrap_into_docblock(w, |w| {
         wrap_item(w, "enum", |w| {
@@ -964,14 +977,9 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
                     match *v.kind {
                         clean::VariantItem(ref var) => match var {
                             clean::Variant::CLike => write!(w, "{}", name),
-                            clean::Variant::Tuple(ref tys) => {
+                            clean::Variant::Tuple(ref s) => {
                                 write!(w, "{}(", name);
-                                for (i, ty) in tys.iter().enumerate() {
-                                    if i > 0 {
-                                        w.write_str(",&nbsp;")
-                                    }
-                                    write!(w, "{}", ty.print(cx));
-                                }
+                                print_tuple_struct_fields(w, cx, s);
                                 w.write_str(")");
                             }
                             clean::Variant::Struct(ref s) => {
@@ -1024,14 +1032,9 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
                 id = id,
                 name = variant.name.as_ref().unwrap()
             );
-            if let clean::VariantItem(clean::Variant::Tuple(ref tys)) = *variant.kind {
+            if let clean::VariantItem(clean::Variant::Tuple(ref s)) = *variant.kind {
                 w.write_str("(");
-                for (i, ty) in tys.iter().enumerate() {
-                    if i > 0 {
-                        w.write_str(",&nbsp;");
-                    }
-                    write!(w, "{}", ty.print(cx));
-                }
+                print_tuple_struct_fields(w, cx, s);
                 w.write_str(")");
             }
             w.write_str("</code>");
@@ -1041,7 +1044,11 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
             document_non_exhaustive(w, variant);
 
             use crate::clean::Variant;
-            if let clean::VariantItem(Variant::Struct(ref s)) = *variant.kind {
+            if let Some((extra, fields)) = match *variant.kind {
+                clean::VariantItem(Variant::Struct(ref s)) => Some(("", &s.fields)),
+                clean::VariantItem(Variant::Tuple(ref fields)) => Some(("Tuple ", fields)),
+                _ => None,
+            } {
                 let variant_id = cx.derive_id(format!(
                     "{}.{}.fields",
                     ItemType::Variant,
@@ -1051,10 +1058,10 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
                 write!(
                     w,
                     "<h3>{extra}Fields of <b>{name}</b></h3><div>",
-                    extra = if s.struct_type == CtorKind::Fn { "Tuple " } else { "" },
+                    extra = extra,
                     name = variant.name.as_ref().unwrap(),
                 );
-                for field in &s.fields {
+                for field in fields {
                     use crate::clean::StructFieldItem;
                     if let StructFieldItem(ref ty) = *field.kind {
                         let id = cx.derive_id(format!(
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index f3eeea6c6ae0b..9453e6d35ee67 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -569,7 +569,18 @@ impl FromWithTcx<clean::Variant> for Variant {
         use clean::Variant::*;
         match variant {
             CLike => Variant::Plain,
-            Tuple(t) => Variant::Tuple(t.into_iter().map(|x| x.into_tcx(tcx)).collect()),
+            Tuple(fields) => Variant::Tuple(
+                fields
+                    .into_iter()
+                    .map(|f| {
+                        if let clean::StructFieldItem(ty) = *f.kind {
+                            ty.into_tcx(tcx)
+                        } else {
+                            unreachable!()
+                        }
+                    })
+                    .collect(),
+            ),
             Struct(s) => Variant::Struct(ids(s.fields)),
         }
     }
diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs
index 819d7d323fd7a..a93880453ba27 100644
--- a/src/librustdoc/passes/stripper.rs
+++ b/src/librustdoc/passes/stripper.rs
@@ -94,8 +94,8 @@ impl<'a> DocFolder for Stripper<'a> {
 
             // implementations of traits are always public.
             clean::ImplItem(ref imp) if imp.trait_.is_some() => true,
-            // Struct variant fields have inherited visibility
-            clean::VariantItem(clean::Variant::Struct(..)) => true,
+            // Variant fields have inherited visibility
+            clean::VariantItem(clean::Variant::Struct(..) | clean::Variant::Tuple(..)) => true,
             _ => false,
         };
 
diff --git a/src/test/rustdoc-json/enums/variant_struct.rs b/src/test/rustdoc-json/enums/variant_struct.rs
new file mode 100644
index 0000000000000..246e6a09007b3
--- /dev/null
+++ b/src/test/rustdoc-json/enums/variant_struct.rs
@@ -0,0 +1,11 @@
+// @has variant_struct.json "$.index[*][?(@.name=='EnumStruct')].visibility" \"public\"
+// @has - "$.index[*][?(@.name=='EnumStruct')].kind" \"enum\"
+pub enum EnumStruct {
+    // @has - "$.index[*][?(@.name=='VariantS')].inner.variant_kind" \"struct\"
+    // @has - "$.index[*][?(@.name=='x')]"
+    // @has - "$.index[*][?(@.name=='y')]"
+    VariantS {
+        x: u32,
+        y: String,
+    },
+}
diff --git a/src/test/rustdoc-json/enums/variant_tuple_struct.rs b/src/test/rustdoc-json/enums/variant_tuple_struct.rs
new file mode 100644
index 0000000000000..d948dc552cdbc
--- /dev/null
+++ b/src/test/rustdoc-json/enums/variant_tuple_struct.rs
@@ -0,0 +1,6 @@
+// @has variant_tuple_struct.json "$.index[*][?(@.name=='EnumTupleStruct')].visibility" \"public\"
+// @has - "$.index[*][?(@.name=='EnumTupleStruct')].kind" \"enum\"
+pub enum EnumTupleStruct {
+    // @has - "$.index[*][?(@.name=='VariantA')].inner.variant_kind" \"tuple\"
+    VariantA(u32, String),
+}
diff --git a/src/test/ui/abi/unsupported.aarch64.stderr b/src/test/ui/abi/unsupported.aarch64.stderr
index fdeb79f93e9f2..225d49e05a3fa 100644
--- a/src/test/ui/abi/unsupported.aarch64.stderr
+++ b/src/test/ui/abi/unsupported.aarch64.stderr
@@ -1,41 +1,47 @@
 error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:24:1
+  --> $DIR/unsupported.rs:26:1
    |
 LL | extern "ptx-kernel" fn ptx() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"amdgpu-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:26:1
+  --> $DIR/unsupported.rs:28:1
    |
 LL | extern "amdgpu-kernel" fn amdgpu() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"wasm"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:28:1
+  --> $DIR/unsupported.rs:30:1
    |
 LL | extern "wasm" fn wasm() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
+error[E0570]: `"aapcs"` is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:32:1
+   |
+LL | extern "aapcs" fn aapcs() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:33:1
+  --> $DIR/unsupported.rs:36:1
    |
 LL | extern "msp430-interrupt" fn msp430() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:35:1
+  --> $DIR/unsupported.rs:38:1
    |
 LL | extern "avr-interrupt" fn avr() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:37:1
+  --> $DIR/unsupported.rs:40:1
    |
 LL | extern "x86-interrupt" fn x86() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:39:1
+  --> $DIR/unsupported.rs:43:1
    |
 LL | extern "stdcall" fn stdcall() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -45,7 +51,7 @@ LL | extern "stdcall" fn stdcall() {}
    = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678>
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:44:1
+  --> $DIR/unsupported.rs:50:1
    |
 LL | extern "thiscall" fn thiscall() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -53,6 +59,6 @@ LL | extern "thiscall" fn thiscall() {}
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678>
 
-error: aborting due to 6 previous errors; 2 warnings emitted
+error: aborting due to 7 previous errors; 2 warnings emitted
 
 For more information about this error, try `rustc --explain E0570`.
diff --git a/src/test/ui/abi/unsupported.arm.stderr b/src/test/ui/abi/unsupported.arm.stderr
new file mode 100644
index 0000000000000..b050ee0aa3148
--- /dev/null
+++ b/src/test/ui/abi/unsupported.arm.stderr
@@ -0,0 +1,58 @@
+error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:26:1
+   |
+LL | extern "ptx-kernel" fn ptx() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0570]: `"amdgpu-kernel"` is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:28:1
+   |
+LL | extern "amdgpu-kernel" fn amdgpu() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0570]: `"wasm"` is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:30:1
+   |
+LL | extern "wasm" fn wasm() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:36:1
+   |
+LL | extern "msp430-interrupt" fn msp430() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:38:1
+   |
+LL | extern "avr-interrupt" fn avr() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:40:1
+   |
+LL | extern "x86-interrupt" fn x86() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: use of calling convention not supported on this target
+  --> $DIR/unsupported.rs:43:1
+   |
+LL | extern "stdcall" fn stdcall() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(unsupported_calling_conventions)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678>
+
+warning: use of calling convention not supported on this target
+  --> $DIR/unsupported.rs:50:1
+   |
+LL | extern "thiscall" fn thiscall() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678>
+
+error: aborting due to 6 previous errors; 2 warnings emitted
+
+For more information about this error, try `rustc --explain E0570`.
diff --git a/src/test/ui/abi/unsupported.i686.stderr b/src/test/ui/abi/unsupported.i686.stderr
index 81b12653d2ee8..7ca93516db989 100644
--- a/src/test/ui/abi/unsupported.i686.stderr
+++ b/src/test/ui/abi/unsupported.i686.stderr
@@ -1,35 +1,35 @@
 error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:24:1
+  --> $DIR/unsupported.rs:26:1
    |
 LL | extern "ptx-kernel" fn ptx() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"amdgpu-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:26:1
+  --> $DIR/unsupported.rs:28:1
    |
 LL | extern "amdgpu-kernel" fn amdgpu() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"wasm"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:28:1
+  --> $DIR/unsupported.rs:30:1
    |
 LL | extern "wasm" fn wasm() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"aapcs"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:30:1
+  --> $DIR/unsupported.rs:32:1
    |
 LL | extern "aapcs" fn aapcs() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:33:1
+  --> $DIR/unsupported.rs:36:1
    |
 LL | extern "msp430-interrupt" fn msp430() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:35:1
+  --> $DIR/unsupported.rs:38:1
    |
 LL | extern "avr-interrupt" fn avr() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/abi/unsupported.rs b/src/test/ui/abi/unsupported.rs
index f0debdcf621e2..9319eac8d30d8 100644
--- a/src/test/ui/abi/unsupported.rs
+++ b/src/test/ui/abi/unsupported.rs
@@ -1,11 +1,13 @@
-// revisions: x64 i686 aarch64
+// revisions: x64 i686 aarch64 arm
 //
 // [x64] needs-llvm-components: x86
-// [x64]compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib
+// [x64] compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib
 // [i686] needs-llvm-components: x86
-// [i686]compile-flags: --target=i686-unknown-linux-gnu --crate-type=rlib
+// [i686] compile-flags: --target=i686-unknown-linux-gnu --crate-type=rlib
 // [aarch64] needs-llvm-components: aarch64
-// [aarch64]compile-flags: --target=aarch64-unknown-linux-gnu --crate-type=rlib
+// [aarch64] compile-flags: --target=aarch64-unknown-linux-gnu --crate-type=rlib
+// [arm] needs-llvm-components: arm
+// [arm] compile-flags: --target=armv7-unknown-linux-gnueabihf --crate-type=rlib
 #![no_core]
 #![feature(
     no_core,
@@ -30,19 +32,25 @@ extern "wasm" fn wasm() {}
 extern "aapcs" fn aapcs() {}
 //[x64]~^ ERROR is not a supported ABI
 //[i686]~^^ ERROR is not a supported ABI
+//[aarch64]~^^^ ERROR is not a supported ABI
 extern "msp430-interrupt" fn msp430() {}
 //~^ ERROR is not a supported ABI
 extern "avr-interrupt" fn avr() {}
 //~^ ERROR is not a supported ABI
 extern "x86-interrupt" fn x86() {}
 //[aarch64]~^ ERROR is not a supported ABI
+//[arm]~^^ ERROR is not a supported ABI
 extern "stdcall" fn stdcall() {}
 //[x64]~^ WARN use of calling convention not supported
 //[x64]~^^ WARN this was previously accepted
 //[aarch64]~^^^ WARN use of calling convention not supported
 //[aarch64]~^^^^ WARN this was previously accepted
+//[arm]~^^^^^ WARN use of calling convention not supported
+//[arm]~^^^^^^ WARN this was previously accepted
 extern "thiscall" fn thiscall() {}
 //[x64]~^ WARN use of calling convention not supported
 //[x64]~^^ WARN this was previously accepted
 //[aarch64]~^^^ WARN use of calling convention not supported
 //[aarch64]~^^^^ WARN this was previously accepted
+//[arm]~^^^^^ WARN use of calling convention not supported
+//[arm]~^^^^^^ WARN this was previously accepted
diff --git a/src/test/ui/abi/unsupported.x64.stderr b/src/test/ui/abi/unsupported.x64.stderr
index 60d067acf174f..f2f52683324db 100644
--- a/src/test/ui/abi/unsupported.x64.stderr
+++ b/src/test/ui/abi/unsupported.x64.stderr
@@ -1,41 +1,41 @@
 error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:24:1
+  --> $DIR/unsupported.rs:26:1
    |
 LL | extern "ptx-kernel" fn ptx() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"amdgpu-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:26:1
+  --> $DIR/unsupported.rs:28:1
    |
 LL | extern "amdgpu-kernel" fn amdgpu() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"wasm"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:28:1
+  --> $DIR/unsupported.rs:30:1
    |
 LL | extern "wasm" fn wasm() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"aapcs"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:30:1
+  --> $DIR/unsupported.rs:32:1
    |
 LL | extern "aapcs" fn aapcs() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:33:1
+  --> $DIR/unsupported.rs:36:1
    |
 LL | extern "msp430-interrupt" fn msp430() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:35:1
+  --> $DIR/unsupported.rs:38:1
    |
 LL | extern "avr-interrupt" fn avr() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:39:1
+  --> $DIR/unsupported.rs:43:1
    |
 LL | extern "stdcall" fn stdcall() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -45,7 +45,7 @@ LL | extern "stdcall" fn stdcall() {}
    = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678>
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:44:1
+  --> $DIR/unsupported.rs:50:1
    |
 LL | extern "thiscall" fn thiscall() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr b/src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr
index b026099f6829b..033ec21ba8408 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr
@@ -4,7 +4,7 @@ error: `~const` is not allowed here
 LL | fn rpit() -> impl ~const T { S }
    |                   ^^^^^^^^
    |
-   = note: only allowed on bounds on traits' associated types, const fns, const impls and its associated functions
+   = note: only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions
 
 error: `~const` is not allowed here
   --> $DIR/tilde-const-invalid-places.rs:11:17
@@ -12,7 +12,7 @@ error: `~const` is not allowed here
 LL | fn apit(_: impl ~const T) {}
    |                 ^^^^^^^^
    |
-   = note: only allowed on bounds on traits' associated types, const fns, const impls and its associated functions
+   = note: only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions
 
 error: `~const` is not allowed here
   --> $DIR/tilde-const-invalid-places.rs:14:50
@@ -20,7 +20,7 @@ error: `~const` is not allowed here
 LL | fn rpit_assoc_bound() -> impl IntoIterator<Item: ~const T> { Some(S) }
    |                                                  ^^^^^^^^
    |
-   = note: only allowed on bounds on traits' associated types, const fns, const impls and its associated functions
+   = note: only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions
 
 error: `~const` is not allowed here
   --> $DIR/tilde-const-invalid-places.rs:17:48
@@ -28,7 +28,7 @@ error: `~const` is not allowed here
 LL | fn apit_assoc_bound(_: impl IntoIterator<Item: ~const T>) {}
    |                                                ^^^^^^^^
    |
-   = note: only allowed on bounds on traits' associated types, const fns, const impls and its associated functions
+   = note: only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions
 
 error: `~const` is not allowed here
   --> $DIR/tilde-const-invalid-places.rs:20:15
@@ -36,7 +36,7 @@ error: `~const` is not allowed here
 LL | fn generic<P: ~const T>() {}
    |               ^^^^^^^^
    |
-   = note: only allowed on bounds on traits' associated types, const fns, const impls and its associated functions
+   = note: only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions
 
 error: `~const` is not allowed here
   --> $DIR/tilde-const-invalid-places.rs:23:31
@@ -44,7 +44,7 @@ error: `~const` is not allowed here
 LL | fn where_clause<P>() where P: ~const T {}
    |                               ^^^^^^^^
    |
-   = note: only allowed on bounds on traits' associated types, const fns, const impls and its associated functions
+   = note: only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions
 
 error: `~const` and `?` are mutually exclusive
   --> $DIR/tilde-const-invalid-places.rs:26:25
diff --git a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-run.rs b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-run.rs
new file mode 100644
index 0000000000000..0cde5b6f84218
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-run.rs
@@ -0,0 +1,41 @@
+// run-pass
+
+#![feature(const_trait_impl)]
+#![feature(const_fn_trait_bound)]
+
+trait Bar {
+    fn bar() -> u8;
+}
+
+trait Foo {
+    #[default_method_body_is_const]
+    fn foo() -> u8 where Self: ~const Bar {
+        <Self as Bar>::bar() * 6
+    }
+}
+
+struct NonConst;
+struct Const;
+
+impl Bar for NonConst {
+    fn bar() -> u8 {
+        3
+    }
+}
+
+impl Foo for NonConst {}
+
+impl const Bar for Const {
+    fn bar() -> u8 {
+        4
+    }
+}
+
+impl const Foo for Const {}
+
+fn main() {
+    const ANS1: u8 = Const::foo();
+    let ans2 = NonConst::foo();
+
+    assert_eq!(ANS1 + ans2, 42);
+}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs
new file mode 100644
index 0000000000000..ae9ab26cdc04a
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs
@@ -0,0 +1,24 @@
+// check-pass
+
+#![feature(const_trait_impl)]
+#![feature(const_fn_trait_bound)]
+
+trait Foo {
+    fn bar() where Self: ~const Foo;
+}
+
+struct S;
+
+impl Foo for S {
+    fn bar() {}
+}
+
+fn baz<T: Foo>() {
+    T::bar();
+}
+
+const fn qux<T: ~const Foo>() {
+    T::bar();
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.rs b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.rs
new file mode 100644
index 0000000000000..d64822d7ce8af
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.rs
@@ -0,0 +1,40 @@
+#![feature(const_fn_trait_bound)]
+#![feature(const_trait_impl)]
+
+trait Bar {}
+
+trait Foo {
+    fn a();
+    fn b() where Self: ~const Bar;
+    fn c<T: ~const Bar>();
+}
+
+const fn test1<T: ~const Foo + Bar>() {
+    T::a();
+    T::b();
+    //~^ ERROR the trait bound
+    T::c::<T>();
+    //~^ ERROR the trait bound
+}
+
+const fn test2<T: ~const Foo + ~const Bar>() {
+    T::a();
+    T::b();
+    T::c::<T>();
+}
+
+fn test3<T: Foo>() {
+    T::a();
+    T::b();
+    //~^ ERROR the trait bound
+    T::c::<T>();
+    //~^ ERROR the trait bound
+}
+
+fn test4<T: Foo + Bar>() {
+    T::a();
+    T::b();
+    T::c::<T>();
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr
new file mode 100644
index 0000000000000..fffb91f98700b
--- /dev/null
+++ b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr
@@ -0,0 +1,67 @@
+error[E0277]: the trait bound `T: Bar` is not satisfied
+  --> $DIR/trait-where-clause.rs:14:5
+   |
+LL |     T::b();
+   |     ^^^^ the trait `Bar` is not implemented for `T`
+   |
+note: required by `Foo::b`
+  --> $DIR/trait-where-clause.rs:8:5
+   |
+LL |     fn b() where Self: ~const Bar;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider further restricting this bound
+   |
+LL | const fn test1<T: ~const Foo + Bar + Bar>() {
+   |                                    +++++
+
+error[E0277]: the trait bound `T: Bar` is not satisfied
+  --> $DIR/trait-where-clause.rs:16:5
+   |
+LL |     T::c::<T>();
+   |     ^^^^^^^^^ the trait `Bar` is not implemented for `T`
+   |
+note: required by `Foo::c`
+  --> $DIR/trait-where-clause.rs:9:5
+   |
+LL |     fn c<T: ~const Bar>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+help: consider further restricting this bound
+   |
+LL | const fn test1<T: ~const Foo + Bar + Bar>() {
+   |                                    +++++
+
+error[E0277]: the trait bound `T: Bar` is not satisfied
+  --> $DIR/trait-where-clause.rs:28:5
+   |
+LL |     T::b();
+   |     ^^^^ the trait `Bar` is not implemented for `T`
+   |
+note: required by `Foo::b`
+  --> $DIR/trait-where-clause.rs:8:5
+   |
+LL |     fn b() where Self: ~const Bar;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider further restricting this bound
+   |
+LL | fn test3<T: Foo + Bar>() {
+   |                 +++++
+
+error[E0277]: the trait bound `T: Bar` is not satisfied
+  --> $DIR/trait-where-clause.rs:30:5
+   |
+LL |     T::c::<T>();
+   |     ^^^^^^^^^ the trait `Bar` is not implemented for `T`
+   |
+note: required by `Foo::c`
+  --> $DIR/trait-where-clause.rs:9:5
+   |
+LL |     fn c<T: ~const Bar>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+help: consider further restricting this bound
+   |
+LL | fn test3<T: Foo + Bar>() {
+   |                 +++++
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/rust-2021/future-prelude-collision-macros.fixed b/src/test/ui/rust-2021/future-prelude-collision-macros.fixed
new file mode 100644
index 0000000000000..a97dc176e1b8b
--- /dev/null
+++ b/src/test/ui/rust-2021/future-prelude-collision-macros.fixed
@@ -0,0 +1,45 @@
+// run-rustfix
+// edition:2018
+// check-pass
+#![warn(rust_2021_prelude_collisions)]
+#![allow(unreachable_code)]
+
+macro_rules! foo {
+    () => {{
+        123;
+        S
+    }};
+}
+
+trait MyTry<T> {
+    fn try_into(self, _: u8);
+}
+
+struct S;
+
+impl MyTry<i32> for S {
+    fn try_into(self, _: u8) {}
+}
+
+trait TryFromU8: Sized {
+    fn try_from(_: u8);
+}
+
+impl TryFromU8 for u32 {
+    fn try_from(_: u8) {}
+}
+
+macro_rules! bar {
+    () => {
+        u32
+    };
+}
+
+fn main() {
+    MyTry::try_into(foo!(), todo!());
+    //~^ WARNING trait method `try_into` will become ambiguous in Rust 2021
+    //~| WARNING this is accepted in the current edition
+    <bar!() as TryFromU8>::try_from(0);
+    //~^ WARNING trait-associated function `try_from` will become ambiguous in Rust 2021
+    //~| WARNING this is accepted in the current edition
+}
diff --git a/src/test/ui/rust-2021/future-prelude-collision-macros.rs b/src/test/ui/rust-2021/future-prelude-collision-macros.rs
new file mode 100644
index 0000000000000..82484b5b3688d
--- /dev/null
+++ b/src/test/ui/rust-2021/future-prelude-collision-macros.rs
@@ -0,0 +1,45 @@
+// run-rustfix
+// edition:2018
+// check-pass
+#![warn(rust_2021_prelude_collisions)]
+#![allow(unreachable_code)]
+
+macro_rules! foo {
+    () => {{
+        123;
+        S
+    }};
+}
+
+trait MyTry<T> {
+    fn try_into(self, _: u8);
+}
+
+struct S;
+
+impl MyTry<i32> for S {
+    fn try_into(self, _: u8) {}
+}
+
+trait TryFromU8: Sized {
+    fn try_from(_: u8);
+}
+
+impl TryFromU8 for u32 {
+    fn try_from(_: u8) {}
+}
+
+macro_rules! bar {
+    () => {
+        u32
+    };
+}
+
+fn main() {
+    foo!().try_into(todo!());
+    //~^ WARNING trait method `try_into` will become ambiguous in Rust 2021
+    //~| WARNING this is accepted in the current edition
+    <bar!()>::try_from(0);
+    //~^ WARNING trait-associated function `try_from` will become ambiguous in Rust 2021
+    //~| WARNING this is accepted in the current edition
+}
diff --git a/src/test/ui/rust-2021/future-prelude-collision-macros.stderr b/src/test/ui/rust-2021/future-prelude-collision-macros.stderr
new file mode 100644
index 0000000000000..4c3543ca782e8
--- /dev/null
+++ b/src/test/ui/rust-2021/future-prelude-collision-macros.stderr
@@ -0,0 +1,25 @@
+warning: trait method `try_into` will become ambiguous in Rust 2021
+  --> $DIR/future-prelude-collision-macros.rs:39:5
+   |
+LL |     foo!().try_into(todo!());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `MyTry::try_into(foo!(), todo!())`
+   |
+note: the lint level is defined here
+  --> $DIR/future-prelude-collision-macros.rs:4:9
+   |
+LL | #![warn(rust_2021_prelude_collisions)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>
+
+warning: trait-associated function `try_from` will become ambiguous in Rust 2021
+  --> $DIR/future-prelude-collision-macros.rs:42:5
+   |
+LL |     <bar!()>::try_from(0);
+   |     ^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `<bar!() as TryFromU8>::try_from`
+   |
+   = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>
+
+warning: 2 warnings emitted
+
diff --git a/src/test/ui/rust-2021/future-prelude-collision-turbofish.fixed b/src/test/ui/rust-2021/future-prelude-collision-turbofish.fixed
new file mode 100644
index 0000000000000..3e76fced774db
--- /dev/null
+++ b/src/test/ui/rust-2021/future-prelude-collision-turbofish.fixed
@@ -0,0 +1,28 @@
+// See https://github.com/rust-lang/rust/issues/88442
+// run-rustfix
+// edition:2018
+// check-pass
+#![allow(unused)]
+#![warn(rust_2021_prelude_collisions)]
+
+trait AnnotatableTryInto {
+    fn try_into<T>(self) -> Result<T, Self::Error>
+    where Self: std::convert::TryInto<T> {
+        std::convert::TryInto::try_into(self)
+    }
+}
+
+impl<T> AnnotatableTryInto for T where T: From<u8> {}
+
+fn main() -> Result<(), &'static str> {
+    let x: u64 = 1;
+    AnnotatableTryInto::try_into::<usize>(x).or(Err("foo"))?.checked_sub(1);
+    //~^ WARNING trait method `try_into` will become ambiguous in Rust 2021
+    //~| WARNING this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
+
+    AnnotatableTryInto::try_into::<usize>(x).or(Err("foo"))?;
+    //~^ WARNING trait method `try_into` will become ambiguous in Rust 2021
+    //~| WARNING this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
+
+    Ok(())
+}
diff --git a/src/test/ui/rust-2021/future-prelude-collision-turbofish.rs b/src/test/ui/rust-2021/future-prelude-collision-turbofish.rs
new file mode 100644
index 0000000000000..abb292ef99284
--- /dev/null
+++ b/src/test/ui/rust-2021/future-prelude-collision-turbofish.rs
@@ -0,0 +1,28 @@
+// See https://github.com/rust-lang/rust/issues/88442
+// run-rustfix
+// edition:2018
+// check-pass
+#![allow(unused)]
+#![warn(rust_2021_prelude_collisions)]
+
+trait AnnotatableTryInto {
+    fn try_into<T>(self) -> Result<T, Self::Error>
+    where Self: std::convert::TryInto<T> {
+        std::convert::TryInto::try_into(self)
+    }
+}
+
+impl<T> AnnotatableTryInto for T where T: From<u8> {}
+
+fn main() -> Result<(), &'static str> {
+    let x: u64 = 1;
+    x.try_into::<usize>().or(Err("foo"))?.checked_sub(1);
+    //~^ WARNING trait method `try_into` will become ambiguous in Rust 2021
+    //~| WARNING this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
+
+    x.try_into::<usize>().or(Err("foo"))?;
+    //~^ WARNING trait method `try_into` will become ambiguous in Rust 2021
+    //~| WARNING this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
+
+    Ok(())
+}
diff --git a/src/test/ui/rust-2021/future-prelude-collision-turbofish.stderr b/src/test/ui/rust-2021/future-prelude-collision-turbofish.stderr
new file mode 100644
index 0000000000000..2de9020bce7ac
--- /dev/null
+++ b/src/test/ui/rust-2021/future-prelude-collision-turbofish.stderr
@@ -0,0 +1,25 @@
+warning: trait method `try_into` will become ambiguous in Rust 2021
+  --> $DIR/future-prelude-collision-turbofish.rs:19:5
+   |
+LL |     x.try_into::<usize>().or(Err("foo"))?.checked_sub(1);
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `AnnotatableTryInto::try_into::<usize>(x)`
+   |
+note: the lint level is defined here
+  --> $DIR/future-prelude-collision-turbofish.rs:6:9
+   |
+LL | #![warn(rust_2021_prelude_collisions)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>
+
+warning: trait method `try_into` will become ambiguous in Rust 2021
+  --> $DIR/future-prelude-collision-turbofish.rs:23:5
+   |
+LL |     x.try_into::<usize>().or(Err("foo"))?;
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `AnnotatableTryInto::try_into::<usize>(x)`
+   |
+   = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/prelude.html>
+
+warning: 2 warnings emitted
+