about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs1
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs1
-rw-r--r--compiler/rustc_driver/src/lib.rs4
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp6
-rw-r--r--compiler/rustc_middle/src/dep_graph/dep_node.rs45
-rw-r--r--compiler/rustc_middle/src/dep_graph/mod.rs3
-rw-r--r--compiler/rustc_middle/src/mir/mono.rs4
-rw-r--r--compiler/rustc_mir/src/monomorphize/collector.rs2
-rw-r--r--compiler/rustc_typeck/src/check/pat.rs57
-rw-r--r--library/alloc/src/sync/tests.rs2
-rw-r--r--library/alloc/src/vec/mod.rs21
-rw-r--r--library/core/src/fmt/mod.rs38
-rw-r--r--library/core/src/iter/adapters/intersperse.rs154
-rw-r--r--library/core/src/iter/adapters/mod.rs2
-rw-r--r--library/core/src/iter/mod.rs4
-rw-r--r--library/core/src/iter/traits/iterator.rs39
-rw-r--r--library/core/src/macros/mod.rs6
-rw-r--r--library/core/src/ops/range.rs23
-rw-r--r--library/core/src/slice/mod.rs8
-rw-r--r--library/core/src/sync/atomic.rs27
-rw-r--r--library/core/tests/iter.rs30
-rw-r--r--library/std/src/io/mod.rs70
-rw-r--r--library/std/src/sys/hermit/mutex.rs5
-rw-r--r--library/std/src/sys/sgx/waitqueue/spin_mutex.rs5
-rw-r--r--library/std/src/sys/unix/ext/process.rs56
-rw-r--r--library/std/src/sys/unix/process/process_fuchsia.rs44
-rw-r--r--library/std/src/sys/unix/process/process_unix.rs18
-rw-r--r--library/std/src/sys/windows/ext/process.rs16
-rw-r--r--library/std/src/thread/mod.rs19
m---------src/doc/book0
m---------src/doc/embedded-book0
m---------src/doc/nomicon0
m---------src/doc/reference0
m---------src/doc/rust-by-example0
-rw-r--r--src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr18
-rw-r--r--src/test/ui/error-codes/E0023.stderr9
-rw-r--r--src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr9
-rw-r--r--src/test/ui/issues/issue-72574-2.stderr5
-rw-r--r--src/test/ui/match/match-pattern-field-mismatch.stderr9
-rw-r--r--src/test/ui/pattern/issue-74539.stderr5
-rw-r--r--src/test/ui/pattern/pat-tuple-underfield.rs55
-rw-r--r--src/test/ui/pattern/pat-tuple-underfield.stderr131
42 files changed, 793 insertions, 158 deletions
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index ccbe7325cc6..955e739b2c1 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -552,7 +552,6 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
 
         unsafe {
             llvm::LLVMRustDIBuilderCreateDebugLocation(
-                utils::debug_context(self).llcontext,
                 line.unwrap_or(UNKNOWN_LINE_NUMBER),
                 col.unwrap_or(UNKNOWN_COLUMN_NUMBER),
                 scope,
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index e359d9f8c9c..eb4f36266db 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -2102,7 +2102,6 @@ extern "C" {
     );
 
     pub fn LLVMRustDIBuilderCreateDebugLocation(
-        Context: &'a Context,
         Line: c_uint,
         Column: c_uint,
         Scope: &'a DIScope,
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index 509f81e1653..f8ceb94916e 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -798,7 +798,7 @@ pub fn version(binary: &str, matches: &getopts::Matches) {
         println!("commit-date: {}", unw(util::commit_date_str()));
         println!("host: {}", config::host_triple());
         println!("release: {}", unw(util::release_str()));
-        if cfg!(llvm) {
+        if cfg!(feature = "llvm") {
             get_builtin_codegen_backend("llvm")().print_version();
         }
     }
@@ -1087,7 +1087,7 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
     }
 
     if cg_flags.iter().any(|x| *x == "passes=list") {
-        if cfg!(llvm) {
+        if cfg!(feature = "llvm") {
             get_builtin_codegen_backend("llvm")().print_passes();
         }
         return None;
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index c0ff62c17be..1d6f00562f1 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -994,11 +994,9 @@ LLVMRustDICompositeTypeReplaceArrays(LLVMRustDIBuilderRef Builder,
 }
 
 extern "C" LLVMMetadataRef
-LLVMRustDIBuilderCreateDebugLocation(LLVMContextRef ContextRef, unsigned Line,
-                                     unsigned Column, LLVMMetadataRef Scope,
+LLVMRustDIBuilderCreateDebugLocation(unsigned Line, unsigned Column,
+                                     LLVMMetadataRef Scope,
                                      LLVMMetadataRef InlinedAt) {
-  LLVMContext &Context = *unwrap(ContextRef);
-
   DebugLoc debug_loc = DebugLoc::get(Line, Column, unwrapDIPtr<MDNode>(Scope),
                                      unwrapDIPtr<MDNode>(InlinedAt));
 
diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs
index b775846bba4..65e5301c96e 100644
--- a/compiler/rustc_middle/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs
@@ -29,9 +29,10 @@
 //!   contained no `DefId` for thing that had been removed.
 //!
 //! `DepNode` definition happens in the `define_dep_nodes!()` macro. This macro
-//! defines the `DepKind` enum and a corresponding `dep_constructor` module. The
-//! `dep_constructor` module links a `DepKind` to the parameters that are needed at
-//! runtime in order to construct a valid `DepNode` fingerprint.
+//! defines the `DepKind` enum. Each `DepKind` has its own parameters that are
+//! needed at runtime in order to construct a valid `DepNode` fingerprint.
+//! However, only `CompileCodegenUnit` is constructed explicitly (with
+//! `make_compile_codegen_unit`).
 //!
 //! Because the macro sees what parameters a given `DepKind` requires, it can
 //! "infer" some properties for each kind of `DepNode`:
@@ -44,22 +45,14 @@
 //!   `DefId` it was computed from. In other cases, too much information gets
 //!   lost during fingerprint computation.
 //!
-//! The `dep_constructor` module, together with `DepNode::new()`, ensures that only
+//! `make_compile_codegen_unit`, together with `DepNode::new()`, ensures that only
 //! valid `DepNode` instances can be constructed. For example, the API does not
 //! allow for constructing parameterless `DepNode`s with anything other
 //! than a zeroed out fingerprint. More generally speaking, it relieves the
 //! user of the `DepNode` API of having to know how to compute the expected
 //! fingerprint for a given set of node parameters.
 
-use crate::mir::interpret::{GlobalId, LitToConstInput};
-use crate::traits;
-use crate::traits::query::{
-    CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
-    CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
-    CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal,
-};
-use crate::ty::subst::{GenericArg, SubstsRef};
-use crate::ty::{self, ParamEnvAnd, Ty, TyCtxt};
+use crate::ty::TyCtxt;
 
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX};
@@ -338,25 +331,6 @@ macro_rules! define_dep_nodes {
             $($variant),*
         }
 
-        #[allow(non_camel_case_types)]
-        pub mod dep_constructor {
-            use super::*;
-
-            $(
-                #[inline(always)]
-                #[allow(unreachable_code, non_snake_case)]
-                pub fn $variant(_tcx: TyCtxt<'_>, $(arg: $tuple_arg_ty)*) -> DepNode {
-                    // tuple args
-                    $({
-                        erase!($tuple_arg_ty);
-                        return DepNode::construct(_tcx, DepKind::$variant, &arg)
-                    })*
-
-                    return DepNode::construct(_tcx, DepKind::$variant, &())
-                }
-            )*
-        }
-
         fn dep_kind_from_label_string(label: &str) -> Result<DepKind, ()> {
             match label {
                 $(stringify!($variant) => Ok(DepKind::$variant),)*
@@ -384,9 +358,16 @@ rustc_dep_node_append!([define_dep_nodes!][ <'tcx>
 
     [anon] TraitSelect,
 
+    // WARNING: if `Symbol` is changed, make sure you update `make_compile_codegen_unit` below.
     [] CompileCodegenUnit(Symbol),
 ]);
 
+// WARNING: `construct` is generic and does not know that `CompileCodegenUnit` takes `Symbol`s as keys.
+// Be very careful changing this type signature!
+crate fn make_compile_codegen_unit(tcx: TyCtxt<'_>, name: Symbol) -> DepNode {
+    DepNode::construct(tcx, DepKind::CompileCodegenUnit, &name)
+}
+
 pub type DepNode = rustc_query_system::dep_graph::DepNode<DepKind>;
 
 // We keep a lot of `DepNode`s in memory during compilation. It's not
diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs
index 22e9cc1cd3e..ea4d8c12997 100644
--- a/compiler/rustc_middle/src/dep_graph/mod.rs
+++ b/compiler/rustc_middle/src/dep_graph/mod.rs
@@ -13,7 +13,8 @@ pub use rustc_query_system::dep_graph::{
     WorkProduct, WorkProductId,
 };
 
-pub use dep_node::{dep_constructor, label_strs, DepKind, DepNode, DepNodeExt};
+crate use dep_node::make_compile_codegen_unit;
+pub use dep_node::{label_strs, DepKind, DepNode, DepNodeExt};
 
 pub type DepGraph = rustc_query_system::dep_graph::DepGraph<DepKind>;
 pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps<DepKind>;
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index f810f6a56a5..6d5d408f86c 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -1,4 +1,4 @@
-use crate::dep_graph::{dep_constructor, DepNode, WorkProduct, WorkProductId};
+use crate::dep_graph::{DepNode, WorkProduct, WorkProductId};
 use crate::ich::{NodeIdHashingMode, StableHashingContext};
 use crate::ty::{subst::InternalSubsts, Instance, InstanceDef, SymbolName, TyCtxt};
 use rustc_attr::InlineAttr;
@@ -362,7 +362,7 @@ impl<'tcx> CodegenUnit<'tcx> {
     }
 
     pub fn codegen_dep_node(&self, tcx: TyCtxt<'tcx>) -> DepNode {
-        dep_constructor::CompileCodegenUnit(tcx, self.name())
+        crate::dep_graph::make_compile_codegen_unit(tcx, self.name())
     }
 }
 
diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs
index a8f2b4d60e1..75f80f69bea 100644
--- a/compiler/rustc_mir/src/monomorphize/collector.rs
+++ b/compiler/rustc_mir/src/monomorphize/collector.rs
@@ -823,7 +823,7 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) ->
     }
 
     if !tcx.is_mir_available(def_id) {
-        bug!("cannot create local mono-item for {:?}", def_id)
+        bug!("no MIR available for {:?}", def_id);
     }
 
     true
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index 5fc573a57ad..ecc6e8599ad 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -15,6 +15,7 @@ use rustc_span::hygiene::DesugaringKind;
 use rustc_span::lev_distance::find_best_match_for_name;
 use rustc_span::source_map::{Span, Spanned};
 use rustc_span::symbol::Ident;
+use rustc_span::{BytePos, DUMMY_SP};
 use rustc_trait_selection::traits::{ObligationCause, Pattern};
 
 use std::cmp;
@@ -1001,7 +1002,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // More generally, the expected type wants a tuple variant with one field of an
         // N-arity-tuple, e.g., `V_i((p_0, .., p_N))`. Meanwhile, the user supplied a pattern
         // with the subpatterns directly in the tuple variant pattern, e.g., `V_i(p_0, .., p_N)`.
-        let missing_parenthesis = match (&expected.kind(), fields, had_err) {
+        let missing_parentheses = match (&expected.kind(), fields, had_err) {
             // #67037: only do this if we could successfully type-check the expected type against
             // the tuple struct pattern. Otherwise the substs could get out of range on e.g.,
             // `let P() = U;` where `P != U` with `struct P<T>(T);`.
@@ -1014,13 +1015,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
             _ => false,
         };
-        if missing_parenthesis {
+        if missing_parentheses {
             let (left, right) = match subpats {
                 // This is the zero case; we aim to get the "hi" part of the `QPath`'s
                 // span as the "lo" and then the "hi" part of the pattern's span as the "hi".
                 // This looks like:
                 //
-                // help: missing parenthesis
+                // help: missing parentheses
                 //   |
                 // L |     let A(()) = A(());
                 //   |          ^  ^
@@ -1029,17 +1030,63 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // last sub-pattern. In the case of `A(x)` the first and last may coincide.
                 // This looks like:
                 //
-                // help: missing parenthesis
+                // help: missing parentheses
                 //   |
                 // L |     let A((x, y)) = A((1, 2));
                 //   |           ^    ^
                 [first, ..] => (first.span.shrink_to_lo(), subpats.last().unwrap().span),
             };
             err.multipart_suggestion(
-                "missing parenthesis",
+                "missing parentheses",
                 vec![(left, "(".to_string()), (right.shrink_to_hi(), ")".to_string())],
                 Applicability::MachineApplicable,
             );
+        } else if fields.len() > subpats.len() {
+            let after_fields_span = if pat_span == DUMMY_SP {
+                pat_span
+            } else {
+                pat_span.with_hi(pat_span.hi() - BytePos(1)).shrink_to_hi()
+            };
+            let all_fields_span = match subpats {
+                [] => after_fields_span,
+                [field] => field.span,
+                [first, .., last] => first.span.to(last.span),
+            };
+
+            // Check if all the fields in the pattern are wildcards.
+            let all_wildcards = subpats.iter().all(|pat| matches!(pat.kind, PatKind::Wild));
+
+            let mut wildcard_sugg = vec!["_"; fields.len() - subpats.len()].join(", ");
+            if !subpats.is_empty() {
+                wildcard_sugg = String::from(", ") + &wildcard_sugg;
+            }
+
+            err.span_suggestion_verbose(
+                after_fields_span,
+                "use `_` to explicitly ignore each field",
+                wildcard_sugg,
+                Applicability::MaybeIncorrect,
+            );
+
+            // Only suggest `..` if more than one field is missing
+            // or the pattern consists of all wildcards.
+            if fields.len() - subpats.len() > 1 || all_wildcards {
+                if subpats.is_empty() || all_wildcards {
+                    err.span_suggestion_verbose(
+                        all_fields_span,
+                        "use `..` to ignore all fields",
+                        String::from(".."),
+                        Applicability::MaybeIncorrect,
+                    );
+                } else {
+                    err.span_suggestion_verbose(
+                        after_fields_span,
+                        "use `..` to ignore the rest of the fields",
+                        String::from(", .."),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+            }
         }
 
         err.emit();
diff --git a/library/alloc/src/sync/tests.rs b/library/alloc/src/sync/tests.rs
index e8e1e66da5e..5067af1d4ff 100644
--- a/library/alloc/src/sync/tests.rs
+++ b/library/alloc/src/sync/tests.rs
@@ -370,7 +370,7 @@ fn test_weak_count_locked() {
         let n = Arc::weak_count(&a2);
         assert!(n < 2, "bad weak count: {}", n);
         #[cfg(miri)] // Miri's scheduler does not guarantee liveness, and thus needs this hint.
-        atomic::spin_loop_hint();
+        std::hint::spin_loop();
     }
     t.join().unwrap();
 }
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 1ca194c3361..ccc4f03a1e5 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -1953,27 +1953,6 @@ impl<T: PartialEq, A: Allocator> Vec<T, A> {
     }
 }
 
-impl<T, A: Allocator> Vec<T, A> {
-    /// Removes the first instance of `item` from the vector if the item exists.
-    ///
-    /// This method will be removed soon.
-    #[unstable(feature = "vec_remove_item", reason = "recently added", issue = "40062")]
-    #[rustc_deprecated(
-        reason = "Removing the first item equal to a needle is already easily possible \
-            with iterators and the current Vec methods. Furthermore, having a method for \
-            one particular case of removal (linear search, only the first item, no swap remove) \
-            but not for others is inconsistent. This method will be removed soon.",
-        since = "1.46.0"
-    )]
-    pub fn remove_item<V>(&mut self, item: &V) -> Option<T>
-    where
-        T: PartialEq<V>,
-    {
-        let pos = self.iter().position(|x| *x == *item)?;
-        Some(self.remove(pos))
-    }
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // Internal methods and functions
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 0c65c1c9eb7..73cf5d138bf 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -456,7 +456,9 @@ impl Display for Arguments<'_> {
 ///
 /// When used with the alternate format specifier `#?`, the output is pretty-printed.
 ///
-/// For more information on formatters, see [the module-level documentation][self].
+/// For more information on formatters, see [the module-level documentation][module].
+///
+/// [module]: ../../std/fmt/index.html
 ///
 /// This trait can be used with `#[derive]` if all fields implement `Debug`. When
 /// `derive`d for structs, it will use the name of the `struct`, then `{`, then a
@@ -602,7 +604,9 @@ pub use macros::Debug;
 /// `Display` is similar to [`Debug`], but `Display` is for user-facing
 /// output, and so cannot be derived.
 ///
-/// For more information on formatters, see [the module-level documentation][self].
+/// For more information on formatters, see [the module-level documentation][module].
+///
+/// [module]: ../../std/fmt/index.html
 ///
 /// # Examples
 ///
@@ -674,7 +678,9 @@ pub trait Display {
 ///
 /// The alternate flag, `#`, adds a `0o` in front of the output.
 ///
-/// For more information on formatters, see [the module-level documentation][self].
+/// For more information on formatters, see [the module-level documentation][module].
+///
+/// [module]: ../../std/fmt/index.html
 ///
 /// # Examples
 ///
@@ -726,7 +732,9 @@ pub trait Octal {
 ///
 /// The alternate flag, `#`, adds a `0b` in front of the output.
 ///
-/// For more information on formatters, see [the module-level documentation][self].
+/// For more information on formatters, see [the module-level documentation][module].
+///
+/// [module]: ../../std/fmt/index.html
 ///
 /// # Examples
 ///
@@ -782,7 +790,9 @@ pub trait Binary {
 ///
 /// The alternate flag, `#`, adds a `0x` in front of the output.
 ///
-/// For more information on formatters, see [the module-level documentation][self].
+/// For more information on formatters, see [the module-level documentation][module].
+///
+/// [module]: ../../std/fmt/index.html
 ///
 /// # Examples
 ///
@@ -835,7 +845,9 @@ pub trait LowerHex {
 ///
 /// The alternate flag, `#`, adds a `0x` in front of the output.
 ///
-/// For more information on formatters, see [the module-level documentation][self].
+/// For more information on formatters, see [the module-level documentation][module].
+///
+/// [module]: ../../std/fmt/index.html
 ///
 /// # Examples
 ///
@@ -883,7 +895,9 @@ pub trait UpperHex {
 /// The `Pointer` trait should format its output as a memory location. This is commonly presented
 /// as hexadecimal.
 ///
-/// For more information on formatters, see [the module-level documentation][self].
+/// For more information on formatters, see [the module-level documentation][module].
+///
+/// [module]: ../../std/fmt/index.html
 ///
 /// # Examples
 ///
@@ -932,7 +946,9 @@ pub trait Pointer {
 ///
 /// The `LowerExp` trait should format its output in scientific notation with a lower-case `e`.
 ///
-/// For more information on formatters, see [the module-level documentation][self].
+/// For more information on formatters, see [the module-level documentation][module].
+///
+/// [module]: ../../std/fmt/index.html
 ///
 /// # Examples
 ///
@@ -981,7 +997,9 @@ pub trait LowerExp {
 ///
 /// The `UpperExp` trait should format its output in scientific notation with an upper-case `E`.
 ///
-/// For more information on formatters, see [the module-level documentation][self].
+/// For more information on formatters, see [the module-level documentation][module].
+///
+/// [module]: ../../std/fmt/index.html
 ///
 /// # Examples
 ///
@@ -1555,7 +1573,7 @@ impl<'a> Formatter<'a> {
     ///     }
     /// }
     ///
-    /// // We set alignment to the left with ">".
+    /// // We set alignment to the right with ">".
     /// assert_eq!(&format!("{:G>3}", Foo), "GGG");
     /// assert_eq!(&format!("{:t>6}", Foo), "tttttt");
     /// ```
diff --git a/library/core/src/iter/adapters/intersperse.rs b/library/core/src/iter/adapters/intersperse.rs
index 36232672549..1d01e9b5fb7 100644
--- a/library/core/src/iter/adapters/intersperse.rs
+++ b/library/core/src/iter/adapters/intersperse.rs
@@ -1,6 +1,9 @@
 use super::Peekable;
 
 /// An iterator adapter that places a separator between all elements.
+///
+/// This `struct` is created by [`Iterator::intersperse`]. See its documentation
+/// for more information.
 #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
 #[derive(Debug, Clone)]
 pub struct Intersperse<I: Iterator>
@@ -40,37 +43,146 @@ where
         }
     }
 
-    fn fold<B, F>(mut self, init: B, mut f: F) -> B
+    fn fold<B, F>(self, init: B, f: F) -> B
     where
         Self: Sized,
         F: FnMut(B, Self::Item) -> B,
     {
-        let mut accum = init;
+        let separator = self.separator;
+        intersperse_fold(self.iter, init, f, move || separator.clone(), self.needs_sep)
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        intersperse_size_hint(&self.iter, self.needs_sep)
+    }
+}
+
+/// An iterator adapter that places a separator between all elements.
+///
+/// This `struct` is created by [`Iterator::intersperse_with`]. See its
+/// documentation for more information.
+#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
+pub struct IntersperseWith<I, G>
+where
+    I: Iterator,
+{
+    separator: G,
+    iter: Peekable<I>,
+    needs_sep: bool,
+}
+
+#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
+impl<I, G> crate::fmt::Debug for IntersperseWith<I, G>
+where
+    I: Iterator + crate::fmt::Debug,
+    I::Item: crate::fmt::Debug,
+    G: crate::fmt::Debug,
+{
+    fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result {
+        f.debug_struct("IntersperseWith")
+            .field("separator", &self.separator)
+            .field("iter", &self.iter)
+            .field("needs_sep", &self.needs_sep)
+            .finish()
+    }
+}
 
-        // Use `peek()` first to avoid calling `next()` on an empty iterator.
-        if !self.needs_sep || self.iter.peek().is_some() {
-            if let Some(x) = self.iter.next() {
-                accum = f(accum, x);
-            }
+#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
+impl<I, G> crate::clone::Clone for IntersperseWith<I, G>
+where
+    I: Iterator + crate::clone::Clone,
+    I::Item: crate::clone::Clone,
+    G: Clone,
+{
+    fn clone(&self) -> Self {
+        IntersperseWith {
+            separator: self.separator.clone(),
+            iter: self.iter.clone(),
+            needs_sep: self.needs_sep.clone(),
         }
+    }
+}
 
-        let element = &self.separator;
+impl<I, G> IntersperseWith<I, G>
+where
+    I: Iterator,
+    G: FnMut() -> I::Item,
+{
+    pub(in crate::iter) fn new(iter: I, separator: G) -> Self {
+        Self { iter: iter.peekable(), separator, needs_sep: false }
+    }
+}
 
-        self.iter.fold(accum, |mut accum, x| {
-            accum = f(accum, element.clone());
-            accum = f(accum, x);
-            accum
-        })
+#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
+impl<I, G> Iterator for IntersperseWith<I, G>
+where
+    I: Iterator,
+    G: FnMut() -> I::Item,
+{
+    type Item = I::Item;
+
+    #[inline]
+    fn next(&mut self) -> Option<I::Item> {
+        if self.needs_sep && self.iter.peek().is_some() {
+            self.needs_sep = false;
+            Some((self.separator)())
+        } else {
+            self.needs_sep = true;
+            self.iter.next()
+        }
+    }
+
+    fn fold<B, F>(self, init: B, f: F) -> B
+    where
+        Self: Sized,
+        F: FnMut(B, Self::Item) -> B,
+    {
+        intersperse_fold(self.iter, init, f, self.separator, self.needs_sep)
     }
 
     fn size_hint(&self) -> (usize, Option<usize>) {
-        let (lo, hi) = self.iter.size_hint();
-        let next_is_elem = !self.needs_sep;
-        let lo = lo.saturating_sub(next_is_elem as usize).saturating_add(lo);
-        let hi = match hi {
-            Some(hi) => hi.saturating_sub(next_is_elem as usize).checked_add(hi),
-            None => None,
-        };
-        (lo, hi)
+        intersperse_size_hint(&self.iter, self.needs_sep)
     }
 }
+
+fn intersperse_size_hint<I>(iter: &I, needs_sep: bool) -> (usize, Option<usize>)
+where
+    I: Iterator,
+{
+    let (lo, hi) = iter.size_hint();
+    let next_is_elem = !needs_sep;
+    let lo = lo.saturating_sub(next_is_elem as usize).saturating_add(lo);
+    let hi = match hi {
+        Some(hi) => hi.saturating_sub(next_is_elem as usize).checked_add(hi),
+        None => None,
+    };
+    (lo, hi)
+}
+
+fn intersperse_fold<I, B, F, G>(
+    mut iter: Peekable<I>,
+    init: B,
+    mut f: F,
+    mut separator: G,
+    needs_sep: bool,
+) -> B
+where
+    I: Iterator,
+    F: FnMut(B, I::Item) -> B,
+    G: FnMut() -> I::Item,
+{
+    let mut accum = init;
+
+    // Use `peek()` first to avoid calling `next()` on an empty iterator.
+    if !needs_sep || iter.peek().is_some() {
+        if let Some(x) = iter.next() {
+            accum = f(accum, x);
+        }
+    }
+
+    iter.fold(accum, |mut accum, x| {
+        accum = f(accum, separator());
+        accum = f(accum, x);
+        accum
+    })
+}
diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs
index 7dfbf32cea7..41a7b13232a 100644
--- a/library/core/src/iter/adapters/mod.rs
+++ b/library/core/src/iter/adapters/mod.rs
@@ -43,7 +43,7 @@ pub use self::flatten::Flatten;
 pub use self::copied::Copied;
 
 #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
-pub use self::intersperse::Intersperse;
+pub use self::intersperse::{Intersperse, IntersperseWith};
 
 #[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")]
 pub use self::map_while::MapWhile;
diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs
index 569de719d03..c57ba2bf626 100644
--- a/library/core/src/iter/mod.rs
+++ b/library/core/src/iter/mod.rs
@@ -395,8 +395,6 @@ pub use self::adapters::Cloned;
 pub use self::adapters::Copied;
 #[stable(feature = "iterator_flatten", since = "1.29.0")]
 pub use self::adapters::Flatten;
-#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
-pub use self::adapters::Intersperse;
 #[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")]
 pub use self::adapters::MapWhile;
 #[unstable(feature = "inplace_iteration", issue = "none")]
@@ -410,6 +408,8 @@ pub use self::adapters::{
     Chain, Cycle, Enumerate, Filter, FilterMap, FlatMap, Fuse, Inspect, Map, Peekable, Rev, Scan,
     Skip, SkipWhile, Take, TakeWhile, Zip,
 };
+#[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
+pub use self::adapters::{Intersperse, IntersperseWith};
 
 pub(crate) use self::adapters::process_results;
 
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index 0023de65d2b..83d339d8f40 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -8,7 +8,7 @@ use crate::ops::{Add, ControlFlow, Try};
 use super::super::TrustedRandomAccess;
 use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse};
 use super::super::{FlatMap, Flatten};
-use super::super::{FromIterator, Intersperse, Product, Sum, Zip};
+use super::super::{FromIterator, Intersperse, IntersperseWith, Product, Sum, Zip};
 use super::super::{
     Inspect, Map, MapWhile, Peekable, Rev, Scan, Skip, SkipWhile, StepBy, Take, TakeWhile,
 };
@@ -571,6 +571,9 @@ pub trait Iterator {
 
     /// Places a copy of `separator` between all elements.
     ///
+    /// In case the separator does not implement [`Clone`] or needs to be
+    /// computed every time, use [`intersperse_with`].
+    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -578,9 +581,12 @@ pub trait Iterator {
     /// ```
     /// #![feature(iter_intersperse)]
     ///
-    /// let hello = ["Hello", "World"].iter().copied().intersperse(" ").collect::<String>();
-    /// assert_eq!(hello, "Hello World");
+    /// let hello = ["Hello", "World", "!"].iter().copied().intersperse(" ").collect::<String>();
+    /// assert_eq!(hello, "Hello World !");
     /// ```
+    ///
+    /// [`Clone`]: crate::clone::Clone
+    /// [`intersperse_with`]: Iterator::intersperse_with
     #[inline]
     #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
     fn intersperse(self, separator: Self::Item) -> Intersperse<Self>
@@ -591,6 +597,33 @@ pub trait Iterator {
         Intersperse::new(self, separator)
     }
 
+    /// Places an element generated by `separator` between all elements.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(iter_intersperse)]
+    ///
+    /// let src = ["Hello", "to", "all", "people", "!!"].iter().copied();
+    ///
+    /// let mut happy_emojis = [" ❤️ ", " 😀 "].iter().copied();
+    /// let separator = || happy_emojis.next().unwrap_or(" 🦀 ");
+    ///
+    /// let result = src.intersperse_with(separator).collect::<String>();
+    /// assert_eq!(result, "Hello ❤️ to 😀 all 🦀 people 🦀 !!");
+    /// ```
+    #[inline]
+    #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
+    fn intersperse_with<G>(self, separator: G) -> IntersperseWith<Self, G>
+    where
+        Self: Sized,
+        G: FnMut() -> Self::Item,
+    {
+        IntersperseWith::new(self, separator)
+    }
+
     /// Takes a closure and creates an iterator which calls that closure on each
     /// element.
     ///
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index 1634aff7b4d..90964bae98c 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -401,7 +401,7 @@ macro_rules! write {
 /// For more information, see [`write!`]. For information on the format string syntax, see
 /// [`std::fmt`].
 ///
-/// [`std::fmt`]: crate::fmt
+/// [`std::fmt`]: ../std/fmt/index.html
 ///
 /// # Examples
 ///
@@ -730,7 +730,7 @@ pub(crate) mod builtin {
     /// [`Display`]: crate::fmt::Display
     /// [`Debug`]: crate::fmt::Debug
     /// [`fmt::Arguments`]: crate::fmt::Arguments
-    /// [`std::fmt`]: crate::fmt
+    /// [`std::fmt`]: ../std/fmt/index.html
     /// [`format!`]: ../std/macro.format.html
     /// [`println!`]: ../std/macro.println.html
     ///
@@ -1194,7 +1194,7 @@ pub(crate) mod builtin {
     /// be provided with or without arguments for formatting. See [`std::fmt`]
     /// for syntax for this form.
     ///
-    /// [`std::fmt`]: crate::fmt
+    /// [`std::fmt`]: ../std/fmt/index.html
     ///
     /// # Examples
     ///
diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs
index 1d67e65e51f..0571dc74b9a 100644
--- a/library/core/src/ops/range.rs
+++ b/library/core/src/ops/range.rs
@@ -678,6 +678,29 @@ pub enum Bound<T> {
     Unbounded,
 }
 
+#[unstable(feature = "bound_as_ref", issue = "80996")]
+impl<T> Bound<T> {
+    /// Converts from `&Bound<T>` to `Bound<&T>`.
+    #[inline]
+    pub fn as_ref(&self) -> Bound<&T> {
+        match *self {
+            Included(ref x) => Included(x),
+            Excluded(ref x) => Excluded(x),
+            Unbounded => Unbounded,
+        }
+    }
+
+    /// Converts from `&mut Bound<T>` to `Bound<&T>`.
+    #[inline]
+    pub fn as_mut(&mut self) -> Bound<&mut T> {
+        match *self {
+            Included(ref mut x) => Included(x),
+            Excluded(ref mut x) => Excluded(x),
+            Unbounded => Unbounded,
+        }
+    }
+}
+
 impl<T: Clone> Bound<&T> {
     /// Map a `Bound<&T>` to a `Bound<T>` by cloning the contents of the bound.
     ///
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 081d80f4876..6de27140594 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -1877,7 +1877,7 @@ impl<T> [T] {
     ///            Some(b"llo".as_ref()));
     /// ```
     #[must_use = "returns the subslice without modifying the original"]
-    #[stable(feature = "slice_strip", since = "1.50.0")]
+    #[stable(feature = "slice_strip", since = "1.51.0")]
     pub fn strip_prefix<P: SlicePattern<Item = T> + ?Sized>(&self, prefix: &P) -> Option<&[T]>
     where
         T: PartialEq,
@@ -1911,7 +1911,7 @@ impl<T> [T] {
     /// assert_eq!(v.strip_suffix(&[50, 30]), None);
     /// ```
     #[must_use = "returns the subslice without modifying the original"]
-    #[stable(feature = "slice_strip", since = "1.50.0")]
+    #[stable(feature = "slice_strip", since = "1.51.0")]
     pub fn strip_suffix<P: SlicePattern<Item = T> + ?Sized>(&self, suffix: &P) -> Option<&[T]>
     where
         T: PartialEq,
@@ -3323,7 +3323,7 @@ pub trait SlicePattern {
     fn as_slice(&self) -> &[Self::Item];
 }
 
-#[stable(feature = "slice_strip", since = "1.50.0")]
+#[stable(feature = "slice_strip", since = "1.51.0")]
 impl<T> SlicePattern for [T] {
     type Item = T;
 
@@ -3333,7 +3333,7 @@ impl<T> SlicePattern for [T] {
     }
 }
 
-#[stable(feature = "slice_strip", since = "1.50.0")]
+#[stable(feature = "slice_strip", since = "1.51.0")]
 impl<T, const N: usize> SlicePattern for [T; N] {
     type Item = T;
 
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index a167f0ffa09..81c9e1d1c10 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -120,21 +120,6 @@ use crate::intrinsics;
 
 use crate::hint::spin_loop;
 
-/// Signals the processor that it is inside a busy-wait spin-loop ("spin lock").
-///
-/// This function is expected to be deprecated in favor of
-/// [`hint::spin_loop`].
-///
-/// **Note**: On platforms that do not support receiving spin-loop hints this function does not
-/// do anything at all.
-///
-/// [`hint::spin_loop`]: crate::hint::spin_loop
-#[inline]
-#[stable(feature = "spin_loop_hint", since = "1.24.0")]
-pub fn spin_loop_hint() {
-    spin_loop()
-}
-
 /// A boolean type which can be safely shared between threads.
 ///
 /// This type has the same in-memory representation as a [`bool`].
@@ -2791,3 +2776,15 @@ impl<T> fmt::Pointer for AtomicPtr<T> {
         fmt::Pointer::fmt(&self.load(Ordering::SeqCst), f)
     }
 }
+
+/// Signals the processor that it is inside a busy-wait spin-loop ("spin lock").
+///
+/// This function is deprecated in favor of [`hint::spin_loop`].
+///
+/// [`hint::spin_loop`]: crate::hint::spin_loop
+#[inline]
+#[stable(feature = "spin_loop_hint", since = "1.24.0")]
+#[rustc_deprecated(since = "1.51.0", reason = "use hint::spin_loop instead")]
+pub fn spin_loop_hint() {
+    spin_loop()
+}
diff --git a/library/core/tests/iter.rs b/library/core/tests/iter.rs
index 7376e7848ef..691767edea6 100644
--- a/library/core/tests/iter.rs
+++ b/library/core/tests/iter.rs
@@ -3508,6 +3508,12 @@ pub fn extend_for_unit() {
 
 #[test]
 fn test_intersperse() {
+    let v = std::iter::empty().intersperse(0u32).collect::<Vec<_>>();
+    assert_eq!(v, vec![]);
+
+    let v = std::iter::once(1).intersperse(0).collect::<Vec<_>>();
+    assert_eq!(v, vec![1]);
+
     let xs = ["a", "", "b", "c"];
     let v: Vec<&str> = xs.iter().map(|x| x.clone()).intersperse(", ").collect();
     let text: String = v.concat();
@@ -3520,6 +3526,9 @@ fn test_intersperse() {
 
 #[test]
 fn test_intersperse_size_hint() {
+    let iter = std::iter::empty::<i32>().intersperse(0);
+    assert_eq!(iter.size_hint(), (0, Some(0)));
+
     let xs = ["a", "", "b", "c"];
     let mut iter = xs.iter().map(|x| x.clone()).intersperse(", ");
     assert_eq!(iter.size_hint(), (7, Some(7)));
@@ -3587,3 +3596,24 @@ fn test_try_fold_specialization_intersperse_err() {
     iter.try_for_each(|item| if item == "b" { None } else { Some(()) });
     assert_eq!(iter.next(), None);
 }
+
+#[test]
+fn test_intersperse_with() {
+    #[derive(PartialEq, Debug)]
+    struct NotClone {
+        u: u32,
+    }
+    let r = vec![NotClone { u: 0 }, NotClone { u: 1 }]
+        .into_iter()
+        .intersperse_with(|| NotClone { u: 2 })
+        .collect::<Vec<_>>();
+    assert_eq!(r, vec![NotClone { u: 0 }, NotClone { u: 2 }, NotClone { u: 1 }]);
+
+    let mut ctr = 100;
+    let separator = || {
+        ctr *= 2;
+        ctr
+    };
+    let r = (0..3).intersperse_with(separator).collect::<Vec<_>>();
+    assert_eq!(r, vec![0, 200, 1, 400, 2]);
+}
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 7ad9e446c59..3f5b7c0b29b 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -366,7 +366,6 @@ where
 {
     let start_len = buf.len();
     let mut g = Guard { len: buf.len(), buf };
-    let ret;
     loop {
         if g.len == g.buf.len() {
             unsafe {
@@ -385,21 +384,20 @@ where
             }
         }
 
-        match r.read(&mut g.buf[g.len..]) {
-            Ok(0) => {
-                ret = Ok(g.len - start_len);
-                break;
+        let buf = &mut g.buf[g.len..];
+        match r.read(buf) {
+            Ok(0) => return Ok(g.len - start_len),
+            Ok(n) => {
+                // We can't allow bogus values from read. If it is too large, the returned vec could have its length
+                // set past its capacity, or if it overflows the vec could be shortened which could create an invalid
+                // string if this is called via read_to_string.
+                assert!(n <= buf.len());
+                g.len += n;
             }
-            Ok(n) => g.len += n,
             Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
-            Err(e) => {
-                ret = Err(e);
-                break;
-            }
+            Err(e) => return Err(e),
         }
     }
-
-    ret
 }
 
 pub(crate) fn default_read_vectored<F>(read: F, bufs: &mut [IoSliceMut<'_>]) -> Result<usize>
@@ -944,6 +942,54 @@ pub trait Read {
     }
 }
 
+/// Read all bytes from a [reader][Read] into a new [`String`].
+///
+/// This is a convenience function for [`Read::read_to_string`]. Using this
+/// function avoids having to create a variable first and provides more type
+/// safety since you can only get the buffer out if there were no errors. (If you
+/// use [`Read::read_to_string`] you have to remember to check whether the read
+/// succeeded because otherwise your buffer will be empty or only partially full.)
+///
+/// # Performance
+///
+/// The downside of this function's increased ease of use and type safety is
+/// that it gives you less control over performance. For example, you can't
+/// pre-allocate memory like you can using [`String::with_capacity`] and
+/// [`Read::read_to_string`]. Also, you can't re-use the buffer if an error
+/// occurs while reading.
+///
+/// In many cases, this function's performance will be adequate and the ease of use
+/// and type safety tradeoffs will be worth it. However, there are cases where you
+/// need more control over performance, and in those cases you should definitely use
+/// [`Read::read_to_string`] directly.
+///
+/// # Errors
+///
+/// This function forces you to handle errors because the output (the `String`)
+/// is wrapped in a [`Result`]. See [`Read::read_to_string`] for the errors
+/// that can occur. If any error occurs, you will get an [`Err`], so you
+/// don't have to worry about your buffer being empty or partially full.
+///
+/// # Examples
+///
+/// ```no_run
+/// #![feature(io_read_to_string)]
+///
+/// # use std::io;
+/// fn main() -> io::Result<()> {
+///     let stdin = io::read_to_string(&mut io::stdin())?;
+///     println!("Stdin was:");
+///     println!("{}", stdin);
+///     Ok(())
+/// }
+/// ```
+#[unstable(feature = "io_read_to_string", issue = "80218")]
+pub fn read_to_string<R: Read>(reader: &mut R) -> Result<String> {
+    let mut buf = String::new();
+    reader.read_to_string(&mut buf)?;
+    Ok(buf)
+}
+
 /// A buffer type used with `Read::read_vectored`.
 ///
 /// It is semantically a wrapper around an `&mut [u8]`, but is guaranteed to be
diff --git a/library/std/src/sys/hermit/mutex.rs b/library/std/src/sys/hermit/mutex.rs
index f988a019cfe..885389ca54c 100644
--- a/library/std/src/sys/hermit/mutex.rs
+++ b/library/std/src/sys/hermit/mutex.rs
@@ -1,9 +1,10 @@
 use crate::cell::UnsafeCell;
 use crate::collections::VecDeque;
 use crate::ffi::c_void;
+use crate::hint;
 use crate::ops::{Deref, DerefMut, Drop};
 use crate::ptr;
-use crate::sync::atomic::{spin_loop_hint, AtomicUsize, Ordering};
+use crate::sync::atomic::{AtomicUsize, Ordering};
 use crate::sys::hermit::abi;
 
 /// This type provides a lock based on busy waiting to realize mutual exclusion
@@ -46,7 +47,7 @@ impl<T> Spinlock<T> {
     fn obtain_lock(&self) {
         let ticket = self.queue.fetch_add(1, Ordering::SeqCst) + 1;
         while self.dequeue.load(Ordering::SeqCst) != ticket {
-            spin_loop_hint();
+            hint::spin_loop();
         }
     }
 
diff --git a/library/std/src/sys/sgx/waitqueue/spin_mutex.rs b/library/std/src/sys/sgx/waitqueue/spin_mutex.rs
index 9140041c584..7f1a671bab4 100644
--- a/library/std/src/sys/sgx/waitqueue/spin_mutex.rs
+++ b/library/std/src/sys/sgx/waitqueue/spin_mutex.rs
@@ -2,8 +2,9 @@
 mod tests;
 
 use crate::cell::UnsafeCell;
+use crate::hint;
 use crate::ops::{Deref, DerefMut};
-use crate::sync::atomic::{spin_loop_hint, AtomicBool, Ordering};
+use crate::sync::atomic::{AtomicBool, Ordering};
 
 #[derive(Default)]
 pub struct SpinMutex<T> {
@@ -32,7 +33,7 @@ impl<T> SpinMutex<T> {
             match self.try_lock() {
                 None => {
                     while self.lock.load(Ordering::Relaxed) {
-                        spin_loop_hint()
+                        hint::spin_loop()
                     }
                 }
                 Some(guard) => return guard,
diff --git a/library/std/src/sys/unix/ext/process.rs b/library/std/src/sys/unix/ext/process.rs
index 3615a8a5ee8..f4c67b225e6 100644
--- a/library/std/src/sys/unix/ext/process.rs
+++ b/library/std/src/sys/unix/ext/process.rs
@@ -9,6 +9,14 @@ use crate::process;
 use crate::sys;
 use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
 
+mod private {
+    /// This trait being unreachable from outside the crate
+    /// prevents other implementations of the `ExitStatusExt` trait,
+    /// which allows potentially adding more trait methods in the future.
+    #[stable(feature = "none", since = "1.51.0")]
+    pub trait Sealed {}
+}
+
 /// Unix-specific extensions to the [`process::Command`] builder.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait CommandExt {
@@ -163,18 +171,48 @@ impl CommandExt for process::Command {
 }
 
 /// Unix-specific extensions to [`process::ExitStatus`].
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
 #[stable(feature = "rust1", since = "1.0.0")]
-pub trait ExitStatusExt {
+pub trait ExitStatusExt: private::Sealed {
     /// Creates a new `ExitStatus` from the raw underlying `i32` return value of
     /// a process.
     #[stable(feature = "exit_status_from", since = "1.12.0")]
     fn from_raw(raw: i32) -> Self;
 
     /// If the process was terminated by a signal, returns that signal.
+    ///
+    /// In other words, if `WIFSIGNALED`, this returns `WTERMSIG`.
     #[stable(feature = "rust1", since = "1.0.0")]
     fn signal(&self) -> Option<i32>;
+
+    /// If the process was terminated by a signal, says whether it dumped core.
+    #[unstable(feature = "unix_process_wait_more", issue = "80695")]
+    fn core_dumped(&self) -> bool;
+
+    /// If the process was stopped by a signal, returns that signal.
+    ///
+    /// In other words, if `WIFSTOPPED`, this returns `WSTOPSIG`.  This is only possible if the status came from
+    /// a `wait` system call which was passed `WUNTRACED`, was then converted into an `ExitStatus`.
+    #[unstable(feature = "unix_process_wait_more", issue = "80695")]
+    fn stopped_signal(&self) -> Option<i32>;
+
+    /// Whether the process was continued from a stopped status.
+    ///
+    /// Ie, `WIFCONTINUED`.  This is only possible if the status came from a `wait` system call
+    /// which was passed `WCONTINUED`, was then converted into an `ExitStatus`.
+    #[unstable(feature = "unix_process_wait_more", issue = "80695")]
+    fn continued(&self) -> bool;
+
+    /// Returns the underlying raw `wait` status.
+    #[unstable(feature = "unix_process_wait_more", issue = "80695")]
+    fn into_raw(self) -> i32;
 }
 
+#[stable(feature = "none", since = "1.51.0")]
+impl private::Sealed for process::ExitStatus {}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl ExitStatusExt for process::ExitStatus {
     fn from_raw(raw: i32) -> Self {
@@ -184,6 +222,22 @@ impl ExitStatusExt for process::ExitStatus {
     fn signal(&self) -> Option<i32> {
         self.as_inner().signal()
     }
+
+    fn core_dumped(&self) -> bool {
+        self.as_inner().core_dumped()
+    }
+
+    fn stopped_signal(&self) -> Option<i32> {
+        self.as_inner().stopped_signal()
+    }
+
+    fn continued(&self) -> bool {
+        self.as_inner().continued()
+    }
+
+    fn into_raw(self) -> i32 {
+        self.as_inner().into_raw().into()
+    }
 }
 
 #[stable(feature = "process_extensions", since = "1.2.0")]
diff --git a/library/std/src/sys/unix/process/process_fuchsia.rs b/library/std/src/sys/unix/process/process_fuchsia.rs
index b64636c3f3d..0d4703d7f50 100644
--- a/library/std/src/sys/unix/process/process_fuchsia.rs
+++ b/library/std/src/sys/unix/process/process_fuchsia.rs
@@ -245,6 +245,50 @@ impl ExitStatus {
     pub fn signal(&self) -> Option<i32> {
         None
     }
+
+    // FIXME: The actually-Unix implementation in process_unix.rs uses WSTOPSIG, WCOREDUMP et al.
+    // I infer from the implementation of `success`, `code` and `signal` above that these are not
+    // available on Fuchsia.
+    //
+    // It does not appear that Fuchsia is Unix-like enough to implement ExitStatus (or indeed many
+    // other things from std::os::unix) properly.  This veneer is always going to be a bodge.  So
+    // while I don't know if these implementations are actually correct, I think they will do for
+    // now at least.
+    pub fn core_dumped(&self) -> bool {
+        false
+    }
+    pub fn stopped_signal(&self) -> Option<i32> {
+        None
+    }
+    pub fn continued(&self) -> bool {
+        false
+    }
+
+    pub fn into_raw(&self) -> c_int {
+        // We don't know what someone who calls into_raw() will do with this value, but it should
+        // have the conventional Unix representation.  Despite the fact that this is not
+        // standardised in SuS or POSIX, all Unix systems encode the signal and exit status the
+        // same way.  (Ie the WIFEXITED, WEXITSTATUS etc. macros have identical behaviour on every
+        // Unix.)
+        //
+        // The caller of `std::os::unix::into_raw` is probably wanting a Unix exit status, and may
+        // do their own shifting and masking, or even pass the status to another computer running a
+        // different Unix variant.
+        //
+        // The other view would be to say that the caller on Fuchsia ought to know that `into_raw`
+        // will give a raw Fuchsia status (whatever that is - I don't know, personally).  That is
+        // not possible here becaause we must return a c_int because that's what Unix (including
+        // SuS and POSIX) say a wait status is, but Fuchsia apparently uses a u64, so it won't
+        // necessarily fit.
+        //
+        // It seems to me that that the right answer would be to provide std::os::fuchsia with its
+        // own ExitStatusExt, rather that trying to provide a not very convincing imitation of
+        // Unix.  Ie, std::os::unix::process:ExitStatusExt ought not to exist on Fuchsia.  But
+        // fixing this up that is beyond the scope of my efforts now.
+        let exit_status_as_if_unix: u8 = self.0.try_into().expect("Fuchsia process return code bigger than 8 bits, but std::os::unix::ExitStatusExt::into_raw() was called to try to convert the value into a traditional Unix-style wait status, which cannot represent values greater than 255.");
+        let wait_status_as_if_unix = (exit_status_as_if_unix as c_int) << 8;
+        wait_status_as_if_unix
+    }
 }
 
 /// Converts a raw `c_int` to a type-safe `ExitStatus` by wrapping it without copying.
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index a590c744356..945b43678a9 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -479,7 +479,23 @@ impl ExitStatus {
     }
 
     pub fn signal(&self) -> Option<i32> {
-        if !self.exited() { Some(libc::WTERMSIG(self.0)) } else { None }
+        if libc::WIFSIGNALED(self.0) { Some(libc::WTERMSIG(self.0)) } else { None }
+    }
+
+    pub fn core_dumped(&self) -> bool {
+        libc::WIFSIGNALED(self.0) && libc::WCOREDUMP(self.0)
+    }
+
+    pub fn stopped_signal(&self) -> Option<i32> {
+        if libc::WIFSTOPPED(self.0) { Some(libc::WSTOPSIG(self.0)) } else { None }
+    }
+
+    pub fn continued(&self) -> bool {
+        libc::WIFCONTINUED(self.0)
+    }
+
+    pub fn into_raw(&self) -> c_int {
+        self.0
     }
 }
 
diff --git a/library/std/src/sys/windows/ext/process.rs b/library/std/src/sys/windows/ext/process.rs
index 61e4c6a1d17..7a92381d660 100644
--- a/library/std/src/sys/windows/ext/process.rs
+++ b/library/std/src/sys/windows/ext/process.rs
@@ -7,6 +7,14 @@ use crate::process;
 use crate::sys;
 use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
 
+mod private {
+    /// This trait being unreachable from outside the crate
+    /// prevents other implementations of the `ExitStatusExt` trait,
+    /// which allows potentially adding more trait methods in the future.
+    #[stable(feature = "none", since = "1.51.0")]
+    pub trait Sealed {}
+}
+
 #[stable(feature = "process_extensions", since = "1.2.0")]
 impl FromRawHandle for process::Stdio {
     unsafe fn from_raw_handle(handle: RawHandle) -> process::Stdio {
@@ -73,8 +81,11 @@ impl IntoRawHandle for process::ChildStderr {
 }
 
 /// Windows-specific extensions to [`process::ExitStatus`].
+///
+/// This trait is sealed: it cannot be implemented outside the standard library.
+/// This is so that future additional methods are not breaking changes.
 #[stable(feature = "exit_status_from", since = "1.12.0")]
-pub trait ExitStatusExt {
+pub trait ExitStatusExt: private::Sealed {
     /// Creates a new `ExitStatus` from the raw underlying `u32` return value of
     /// a process.
     #[stable(feature = "exit_status_from", since = "1.12.0")]
@@ -88,6 +99,9 @@ impl ExitStatusExt for process::ExitStatus {
     }
 }
 
+#[stable(feature = "none", since = "1.51.0")]
+impl private::Sealed for process::ExitStatus {}
+
 /// Windows-specific extensions to the [`process::Command`] builder.
 #[stable(feature = "windows_process_extensions", since = "1.16.0")]
 pub trait CommandExt {
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 5d65f960fcd..0d004a516f5 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -1186,32 +1186,37 @@ impl fmt::Debug for Thread {
 /// the [`Error`](crate::error::Error) trait.
 ///
 /// Thus, a sensible way to handle a thread panic is to either:
-/// 1. `unwrap` the `Result<T>`, propagating the panic
+///
+/// 1. propagate the panic with [`std::panic::resume_unwind`]
 /// 2. or in case the thread is intended to be a subsystem boundary
 /// that is supposed to isolate system-level failures,
-/// match on the `Err` variant and handle the panic in an appropriate way.
+/// match on the `Err` variant and handle the panic in an appropriate way
 ///
 /// A thread that completes without panicking is considered to exit successfully.
 ///
 /// # Examples
 ///
+/// Matching on the result of a joined thread:
+///
 /// ```no_run
-/// use std::thread;
-/// use std::fs;
+/// use std::{fs, thread, panic};
 ///
 /// fn copy_in_thread() -> thread::Result<()> {
-///     thread::spawn(move || { fs::copy("foo.txt", "bar.txt").unwrap(); }).join()
+///     thread::spawn(|| {
+///         fs::copy("foo.txt", "bar.txt").unwrap();
+///     }).join()
 /// }
 ///
 /// fn main() {
 ///     match copy_in_thread() {
-///         Ok(_) => println!("this is fine"),
-///         Err(_) => println!("thread panicked"),
+///         Ok(_) => println!("copy succeeded"),
+///         Err(e) => panic::resume_unwind(e),
 ///     }
 /// }
 /// ```
 ///
 /// [`Result`]: crate::result::Result
+/// [`std::panic::resume_unwind`]: crate::panic::resume_unwind
 #[stable(feature = "rust1", since = "1.0.0")]
 pub type Result<T> = crate::result::Result<T, Box<dyn Any + Send + 'static>>;
 
diff --git a/src/doc/book b/src/doc/book
-Subproject 5bb44f8b5b0aa105c8b22602e9b18800484afa2
+Subproject ac57a0ddd23d173b26731ccf939f3ba72975327
diff --git a/src/doc/embedded-book b/src/doc/embedded-book
-Subproject ba34b8a968f9531d38c4dc4411d5568b7c076bf
+Subproject ceec19e873be87c6ee5666b030c6bb612f889a9
diff --git a/src/doc/nomicon b/src/doc/nomicon
-Subproject a5a48441d411f61556b57d762b03d6874afe575
+Subproject a8584998eacdea7106a1dfafcbf6c1c06fcdf92
diff --git a/src/doc/reference b/src/doc/reference
-Subproject b278478b766178491a8b6f67afa4bcd6b64d977
+Subproject 50af691f838937c300b47812d0507c6d88c14f9
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 1cce0737d6a7d3ceafb139b4a206861fb1dcb2a
+Subproject 03e23af01f0b4f83a3a513da280e1ca92587f2e
diff --git a/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr b/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr
index 0e7174e5b19..c270593cac7 100644
--- a/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr
+++ b/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr
@@ -31,6 +31,15 @@ LL | struct TupleStruct<S, T>(S, T);
 ...
 LL |     TupleStruct(_) = TupleStruct(1, 2);
    |     ^^^^^^^^^^^^^^ expected 2 fields, found 1
+   |
+help: use `_` to explicitly ignore each field
+   |
+LL |     TupleStruct(_, _) = TupleStruct(1, 2);
+   |                  ^^^
+help: use `..` to ignore all fields
+   |
+LL |     TupleStruct(..) = TupleStruct(1, 2);
+   |                 ^^
 
 error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields
   --> $DIR/tuple_struct_destructure_fail.rs:34:5
@@ -49,6 +58,15 @@ LL |     SingleVariant(S, T)
 ...
 LL |     Enum::SingleVariant(_) = Enum::SingleVariant(1, 2);
    |     ^^^^^^^^^^^^^^^^^^^^^^ expected 2 fields, found 1
+   |
+help: use `_` to explicitly ignore each field
+   |
+LL |     Enum::SingleVariant(_, _) = Enum::SingleVariant(1, 2);
+   |                          ^^^
+help: use `..` to ignore all fields
+   |
+LL |     Enum::SingleVariant(..) = Enum::SingleVariant(1, 2);
+   |                         ^^
 
 error[E0070]: invalid left-hand side of assignment
   --> $DIR/tuple_struct_destructure_fail.rs:40:12
diff --git a/src/test/ui/error-codes/E0023.stderr b/src/test/ui/error-codes/E0023.stderr
index a3610099294..832eba69722 100644
--- a/src/test/ui/error-codes/E0023.stderr
+++ b/src/test/ui/error-codes/E0023.stderr
@@ -6,6 +6,11 @@ LL |     Apple(String, String),
 ...
 LL |         Fruit::Apple(a) => {},
    |         ^^^^^^^^^^^^^^^ expected 2 fields, found 1
+   |
+help: use `_` to explicitly ignore each field
+   |
+LL |         Fruit::Apple(a, _) => {},
+   |                       ^^^
 
 error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields
   --> $DIR/E0023.rs:12:9
@@ -34,7 +39,7 @@ LL |     Orange((String, String)),
 LL |         Fruit::Orange(a, b) => {},
    |         ^^^^^^^^^^^^^^^^^^^ expected 1 field, found 2
    |
-help: missing parenthesis
+help: missing parentheses
    |
 LL |         Fruit::Orange((a, b)) => {},
    |                       ^    ^
@@ -48,7 +53,7 @@ LL |     Banana(()),
 LL |         Fruit::Banana() => {},
    |         ^^^^^^^^^^^^^^^ expected 1 field, found 0
    |
-help: missing parenthesis
+help: missing parentheses
    |
 LL |         Fruit::Banana(()) => {},
    |                      ^  ^
diff --git a/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr b/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr
index 6e8ea6bf618..9bdbf0bf9f4 100644
--- a/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr
+++ b/src/test/ui/issues/issue-67037-pat-tup-scrut-ty-diff-less-fields.stderr
@@ -17,6 +17,15 @@ LL | struct P<T>(T); // 1 type parameter wanted
 ...
 LL |     let P() = U {};
    |         ^^^ expected 1 field, found 0
+   |
+help: use `_` to explicitly ignore each field
+   |
+LL |     let P(_) = U {};
+   |           ^
+help: use `..` to ignore all fields
+   |
+LL |     let P(..) = U {};
+   |           ^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-72574-2.stderr b/src/test/ui/issues/issue-72574-2.stderr
index 0a9c868af7a..a1e8ec1677d 100644
--- a/src/test/ui/issues/issue-72574-2.stderr
+++ b/src/test/ui/issues/issue-72574-2.stderr
@@ -26,6 +26,11 @@ LL | struct Binder(i32, i32, i32);
 ...
 LL |         Binder(_a, _x @ ..) => {}
    |         ^^^^^^^^^^^^^^^^^^^ expected 3 fields, found 2
+   |
+help: use `_` to explicitly ignore each field
+   |
+LL |         Binder(_a, _x @ .., _) => {}
+   |                           ^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/match/match-pattern-field-mismatch.stderr b/src/test/ui/match/match-pattern-field-mismatch.stderr
index c2298d6fbbf..37839482b31 100644
--- a/src/test/ui/match/match-pattern-field-mismatch.stderr
+++ b/src/test/ui/match/match-pattern-field-mismatch.stderr
@@ -6,6 +6,15 @@ LL |         Rgb(usize, usize, usize),
 ...
 LL |           Color::Rgb(_, _) => { }
    |           ^^^^^^^^^^^^^^^^ expected 3 fields, found 2
+   |
+help: use `_` to explicitly ignore each field
+   |
+LL |           Color::Rgb(_, _, _) => { }
+   |                          ^^^
+help: use `..` to ignore all fields
+   |
+LL |           Color::Rgb(..) => { }
+   |                      ^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/pattern/issue-74539.stderr b/src/test/ui/pattern/issue-74539.stderr
index cbc90b5397d..f7644c19ea0 100644
--- a/src/test/ui/pattern/issue-74539.stderr
+++ b/src/test/ui/pattern/issue-74539.stderr
@@ -26,6 +26,11 @@ LL |     A(u8, u8),
 ...
 LL |         E::A(x @ ..) => {
    |         ^^^^^^^^^^^^ expected 2 fields, found 1
+   |
+help: use `_` to explicitly ignore each field
+   |
+LL |         E::A(x @ .., _) => {
+   |                    ^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/pattern/pat-tuple-underfield.rs b/src/test/ui/pattern/pat-tuple-underfield.rs
new file mode 100644
index 00000000000..ed852a47bb4
--- /dev/null
+++ b/src/test/ui/pattern/pat-tuple-underfield.rs
@@ -0,0 +1,55 @@
+struct S(i32, f32);
+enum E {
+    S(i32, f32),
+}
+struct Point4(i32, i32, i32, i32);
+
+fn main() {
+    match S(0, 1.0) {
+        S(x) => {}
+        //~^ ERROR this pattern has 1 field, but the corresponding tuple struct has 2 fields
+        //~| HELP use `_` to explicitly ignore each field
+    }
+    match S(0, 1.0) {
+        S(_) => {}
+        //~^ ERROR this pattern has 1 field, but the corresponding tuple struct has 2 fields
+        //~| HELP use `_` to explicitly ignore each field
+        //~| HELP use `..` to ignore all fields
+    }
+    match S(0, 1.0) {
+        S() => {}
+        //~^ ERROR this pattern has 0 fields, but the corresponding tuple struct has 2 fields
+        //~| HELP use `_` to explicitly ignore each field
+        //~| HELP use `..` to ignore all fields
+    }
+
+    match E::S(0, 1.0) {
+        E::S(x) => {}
+        //~^ ERROR this pattern has 1 field, but the corresponding tuple variant has 2 fields
+        //~| HELP use `_` to explicitly ignore each field
+    }
+    match E::S(0, 1.0) {
+        E::S(_) => {}
+        //~^ ERROR this pattern has 1 field, but the corresponding tuple variant has 2 fields
+        //~| HELP use `_` to explicitly ignore each field
+        //~| HELP use `..` to ignore all fields
+    }
+    match E::S(0, 1.0) {
+        E::S() => {}
+        //~^ ERROR this pattern has 0 fields, but the corresponding tuple variant has 2 fields
+        //~| HELP use `_` to explicitly ignore each field
+        //~| HELP use `..` to ignore all fields
+    }
+    match E::S(0, 1.0) {
+        E::S => {}
+        //~^ ERROR expected unit struct, unit variant or constant, found tuple variant `E::S`
+        //~| HELP use the tuple variant pattern syntax instead
+    }
+
+    match Point4(0, 1, 2, 3) {
+        Point4(   a   ,     _    ) => {}
+        //~^ ERROR this pattern has 2 fields, but the corresponding tuple struct has 4 fields
+        //~| HELP use `_` to explicitly ignore each field
+        //~| HELP use `..` to ignore the rest of the fields
+    }
+}
diff --git a/src/test/ui/pattern/pat-tuple-underfield.stderr b/src/test/ui/pattern/pat-tuple-underfield.stderr
new file mode 100644
index 00000000000..76323d9a7bf
--- /dev/null
+++ b/src/test/ui/pattern/pat-tuple-underfield.stderr
@@ -0,0 +1,131 @@
+error[E0532]: expected unit struct, unit variant or constant, found tuple variant `E::S`
+  --> $DIR/pat-tuple-underfield.rs:44:9
+   |
+LL |     S(i32, f32),
+   |     ----------- `E::S` defined here
+...
+LL |         E::S => {}
+   |         ^^^^ help: use the tuple variant pattern syntax instead: `E::S(_, _)`
+
+error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 2 fields
+  --> $DIR/pat-tuple-underfield.rs:9:9
+   |
+LL | struct S(i32, f32);
+   | ------------------- tuple struct defined here
+...
+LL |         S(x) => {}
+   |         ^^^^ expected 2 fields, found 1
+   |
+help: use `_` to explicitly ignore each field
+   |
+LL |         S(x, _) => {}
+   |            ^^^
+
+error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 2 fields
+  --> $DIR/pat-tuple-underfield.rs:14:9
+   |
+LL | struct S(i32, f32);
+   | ------------------- tuple struct defined here
+...
+LL |         S(_) => {}
+   |         ^^^^ expected 2 fields, found 1
+   |
+help: use `_` to explicitly ignore each field
+   |
+LL |         S(_, _) => {}
+   |            ^^^
+help: use `..` to ignore all fields
+   |
+LL |         S(..) => {}
+   |           ^^
+
+error[E0023]: this pattern has 0 fields, but the corresponding tuple struct has 2 fields
+  --> $DIR/pat-tuple-underfield.rs:20:9
+   |
+LL | struct S(i32, f32);
+   | ------------------- tuple struct defined here
+...
+LL |         S() => {}
+   |         ^^^ expected 2 fields, found 0
+   |
+help: use `_` to explicitly ignore each field
+   |
+LL |         S(_, _) => {}
+   |           ^^^^
+help: use `..` to ignore all fields
+   |
+LL |         S(..) => {}
+   |           ^^
+
+error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields
+  --> $DIR/pat-tuple-underfield.rs:27:9
+   |
+LL |     S(i32, f32),
+   |     ----------- tuple variant defined here
+...
+LL |         E::S(x) => {}
+   |         ^^^^^^^ expected 2 fields, found 1
+   |
+help: use `_` to explicitly ignore each field
+   |
+LL |         E::S(x, _) => {}
+   |               ^^^
+
+error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields
+  --> $DIR/pat-tuple-underfield.rs:32:9
+   |
+LL |     S(i32, f32),
+   |     ----------- tuple variant defined here
+...
+LL |         E::S(_) => {}
+   |         ^^^^^^^ expected 2 fields, found 1
+   |
+help: use `_` to explicitly ignore each field
+   |
+LL |         E::S(_, _) => {}
+   |               ^^^
+help: use `..` to ignore all fields
+   |
+LL |         E::S(..) => {}
+   |              ^^
+
+error[E0023]: this pattern has 0 fields, but the corresponding tuple variant has 2 fields
+  --> $DIR/pat-tuple-underfield.rs:38:9
+   |
+LL |     S(i32, f32),
+   |     ----------- tuple variant defined here
+...
+LL |         E::S() => {}
+   |         ^^^^^^ expected 2 fields, found 0
+   |
+help: use `_` to explicitly ignore each field
+   |
+LL |         E::S(_, _) => {}
+   |              ^^^^
+help: use `..` to ignore all fields
+   |
+LL |         E::S(..) => {}
+   |              ^^
+
+error[E0023]: this pattern has 2 fields, but the corresponding tuple struct has 4 fields
+  --> $DIR/pat-tuple-underfield.rs:50:9
+   |
+LL | struct Point4(i32, i32, i32, i32);
+   | ---------------------------------- tuple struct defined here
+...
+LL |         Point4(   a   ,     _    ) => {}
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 4 fields, found 2
+   |
+help: use `_` to explicitly ignore each field
+   |
+LL |         Point4(   a   ,     _    , _, _) => {}
+   |                                  ^^^^^^
+help: use `..` to ignore the rest of the fields
+   |
+LL |         Point4(   a   ,     _    , ..) => {}
+   |                                  ^^^^
+
+error: aborting due to 8 previous errors
+
+Some errors have detailed explanations: E0023, E0532.
+For more information about an error, try `rustc --explain E0023`.