about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-06-15 20:15:23 +0000
committerbors <bors@rust-lang.org>2021-06-15 20:15:23 +0000
commit607d6b00d4e0e0475b8de9d0c870b7126fdcdf6b (patch)
treee32f610c6985de82f3f7076e4239c9b2f55e353d
parent246571a846e29691bd535d531365acd318857207 (diff)
parent74cc63a7a5ded7c4c0e12cd5e4dc4838be914b78 (diff)
downloadrust-607d6b00d4e0e0475b8de9d0c870b7126fdcdf6b.tar.gz
rust-607d6b00d4e0e0475b8de9d0c870b7126fdcdf6b.zip
Auto merge of #86321 - JohnTitor:rollup-q61c8q4, r=JohnTitor
Rollup of 10 pull requests

Successful merges:

 - #80269 (Explain non-dropped sender recv in docs)
 - #82179 (Add functions `Duration::try_from_secs_{f32, f64}`)
 - #85608 (Stabilize `ops::ControlFlow` (just the type))
 - #85792 (Refactor windows sockets impl methods)
 - #86220 (Improve maybe_uninit_extra docs)
 - #86277 (Remove must_use from ALLOWED_ATTRIBUTES)
 - #86285 (:arrow_up: rust-analyzer)
 - #86294 (Stabilize {std, core}::prelude::rust_*.)
 - #86306 (Add mailmap entries for myself)
 - #86314 (Remove trailing triple backticks in `mut_keyword` docs)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--.mailmap2
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs2
-rw-r--r--compiler/rustc_resolve/src/lib.rs1
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_traits/src/lib.rs1
-rw-r--r--library/core/src/iter/traits/iterator.rs41
-rw-r--r--library/core/src/mem/maybe_uninit.rs80
-rw-r--r--library/core/src/ops/control_flow.rs6
-rw-r--r--library/core/src/ops/try_trait.rs5
-rw-r--r--library/core/src/prelude/mod.rs16
-rw-r--r--library/core/src/time.rs152
-rw-r--r--library/core/tests/lib.rs1
-rw-r--r--library/std/src/error.rs3
-rw-r--r--library/std/src/keyword_docs.rs3
-rw-r--r--library/std/src/lib.rs2
-rw-r--r--library/std/src/prelude/mod.rs32
-rw-r--r--library/std/src/sync/mpsc/mod.rs53
-rw-r--r--library/std/src/sys/windows/c.rs1
-rw-r--r--library/std/src/sys/windows/net.rs305
-rw-r--r--src/librustdoc/html/render/mod.rs10
-rw-r--r--src/test/rustdoc/attributes.rs8
-rw-r--r--src/test/rustdoc/cap-lints.rs3
-rw-r--r--src/test/rustdoc/must-use.rs11
-rw-r--r--src/test/rustdoc/trait-attributes.rs21
m---------src/tools/rust-analyzer35
25 files changed, 516 insertions, 279 deletions
diff --git a/.mailmap b/.mailmap
index 213aa6eff66..8cb74824d93 100644
--- a/.mailmap
+++ b/.mailmap
@@ -166,6 +166,8 @@ lcnr <bastian_kauschke@hotmail.de>
 Lee Jeffery <leejeffery@gmail.com> Lee Jeffery <lee@leejeffery.co.uk>
 Lee Wondong <wdlee91@gmail.com>
 Lennart Kudling <github@kudling.de>
+Léo Lanteri Thauvin <leseulartichaut@gmail.com>
+Léo Lanteri Thauvin <leseulartichaut@gmail.com> <38361244+LeSeulArtichaut@users.noreply.github.com>
 Léo Testard <leo.testard@gmail.com>
 Lindsey Kuper <lindsey@composition.al> <lindsey@rockstargirl.org>
 Lindsey Kuper <lindsey@composition.al> <lkuper@mozilla.com>
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index dbab7e15484..9592c1d2fab 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -331,7 +331,7 @@ pub fn lower_crate<'a, 'hir>(
         lifetimes_to_define: Vec::new(),
         is_collecting_in_band_lifetimes: false,
         in_scope_lifetimes: Vec::new(),
-        allow_try_trait: Some([sym::control_flow_enum, sym::try_trait_v2][..].into()),
+        allow_try_trait: Some([sym::try_trait_v2][..].into()),
         allow_gen_future: Some([sym::gen_future][..].into()),
     }
     .lower_crate(krate)
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 6d5531d3307..00f0fe4a288 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -11,7 +11,6 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(box_patterns)]
 #![feature(bool_to_option)]
-#![feature(control_flow_enum)]
 #![feature(crate_visibility_modifier)]
 #![feature(format_args_capture)]
 #![feature(iter_zip)]
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index fb37c5e9c1e..a96d37c652d 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -416,7 +416,6 @@ symbols! {
         constructor,
         contents,
         context,
-        control_flow_enum,
         convert,
         copy,
         copy_closures,
diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs
index 7b688cd3e21..d0b05beb4e6 100644
--- a/compiler/rustc_traits/src/lib.rs
+++ b/compiler/rustc_traits/src/lib.rs
@@ -4,7 +4,6 @@
 #![feature(crate_visibility_modifier)]
 #![feature(in_band_lifetimes)]
 #![feature(nll)]
-#![feature(control_flow_enum)]
 #![recursion_limit = "256"]
 
 #[macro_use]
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index 11dea400a46..78d317096b4 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -1959,6 +1959,31 @@ pub trait Iterator {
     /// assert_eq!(it.len(), 2);
     /// assert_eq!(it.next(), Some(&40));
     /// ```
+    ///
+    /// While you cannot `break` from a closure, the [`crate::ops::ControlFlow`]
+    /// type allows a similar idea:
+    ///
+    /// ```
+    /// use std::ops::ControlFlow;
+    ///
+    /// let triangular = (1..30).try_fold(0_i8, |prev, x| {
+    ///     if let Some(next) = prev.checked_add(x) {
+    ///         ControlFlow::Continue(next)
+    ///     } else {
+    ///         ControlFlow::Break(prev)
+    ///     }
+    /// });
+    /// assert_eq!(triangular, ControlFlow::Break(120));
+    ///
+    /// let triangular = (1..30).try_fold(0_u64, |prev, x| {
+    ///     if let Some(next) = prev.checked_add(x) {
+    ///         ControlFlow::Continue(next)
+    ///     } else {
+    ///         ControlFlow::Break(prev)
+    ///     }
+    /// });
+    /// assert_eq!(triangular, ControlFlow::Continue(435));
+    /// ```
     #[inline]
     #[stable(feature = "iterator_try_fold", since = "1.27.0")]
     fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
@@ -2001,6 +2026,22 @@ pub trait Iterator {
     /// // It short-circuited, so the remaining items are still in the iterator:
     /// assert_eq!(it.next(), Some("stale_bread.json"));
     /// ```
+    ///
+    /// The [`crate::ops::ControlFlow`] type can be used with this method for the
+    /// situations in which you'd use `break` and `continue` in a normal loop:
+    ///
+    /// ```
+    /// use std::ops::ControlFlow;
+    ///
+    /// let r = (2..100).try_for_each(|x| {
+    ///     if 323 % x == 0 {
+    ///         return ControlFlow::Break(x)
+    ///     }
+    ///
+    ///     ControlFlow::Continue(())
+    /// });
+    /// assert_eq!(r, ControlFlow::Break(17));
+    /// ```
     #[inline]
     #[stable(feature = "iterator_try_fold", since = "1.27.0")]
     fn try_for_each<F, R>(&mut self, f: F) -> R
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs
index 623fd745a5e..de3367e5e52 100644
--- a/library/core/src/mem/maybe_uninit.rs
+++ b/library/core/src/mem/maybe_uninit.rs
@@ -402,10 +402,60 @@ impl<T> MaybeUninit<T> {
         u
     }
 
-    /// Sets the value of the `MaybeUninit<T>`. This overwrites any previous value
-    /// without dropping it, so be careful not to use this twice unless you want to
-    /// skip running the destructor. For your convenience, this also returns a mutable
-    /// reference to the (now safely initialized) contents of `self`.
+    /// Sets the value of the `MaybeUninit<T>`.
+    ///
+    /// This overwrites any previous value without dropping it, so be careful
+    /// not to use this twice unless you want to skip running the destructor.
+    /// For your convenience, this also returns a mutable reference to the
+    /// (now safely initialized) contents of `self`.
+    ///
+    /// As the content is stored inside a `MaybeUninit`, the destructor is not
+    /// ran for the inner data if the MaybeUninit leaves scope without a call to
+    /// [`assume_init`], [`assume_init_drop`], or similar. Code that receives
+    /// the mutable reference returned by this function needs to keep this in
+    /// mind. The safety model of Rust regards leaks as safe, but they are
+    /// usually still undesirable. This being said, the mutable reference
+    /// behaves like any other mutable reference would, so assigning a new value
+    /// to it will drop the old content.
+    ///
+    /// [`assume_init`]: Self::assume_init
+    /// [`assume_init_drop`]: Self::assume_init_drop
+    ///
+    /// # Examples
+    ///
+    /// Correct usage of this method:
+    ///
+    /// ```rust
+    /// #![feature(maybe_uninit_extra)]
+    /// use std::mem::MaybeUninit;
+    ///
+    /// let mut x = MaybeUninit::<Vec<u8>>::uninit();
+    ///
+    /// {
+    ///     let hello = x.write((&b"Hello, world!").to_vec());
+    ///     // Setting hello does not leak prior allocations, but drops them
+    ///     *hello = (&b"Hello").to_vec();
+    ///     hello[0] = 'h' as u8;
+    /// }
+    /// // x is initialized now:
+    /// let s = unsafe { x.assume_init() };
+    /// assert_eq!(b"hello", s.as_slice());
+    /// ```
+    ///
+    /// This usage of the method causes a leak:
+    ///
+    /// ```rust
+    /// #![feature(maybe_uninit_extra)]
+    /// use std::mem::MaybeUninit;
+    ///
+    /// let mut x = MaybeUninit::<String>::uninit();
+    ///
+    /// x.write("Hello".to_string());
+    /// // This leaks the contained string:
+    /// x.write("hello".to_string());
+    /// // x is initialized now:
+    /// let s = unsafe { x.assume_init() };
+    /// ```
     #[unstable(feature = "maybe_uninit_extra", issue = "63567")]
     #[rustc_const_unstable(feature = "maybe_uninit_extra", issue = "63567")]
     #[inline(always)]
@@ -564,9 +614,11 @@ impl<T> MaybeUninit<T> {
     /// behavior. The [type-level documentation][inv] contains more information about
     /// this initialization invariant.
     ///
-    /// Moreover, this leaves a copy of the same data behind in the `MaybeUninit<T>`. When using
-    /// multiple copies of the data (by calling `assume_init_read` multiple times, or first
-    /// calling `assume_init_read` and then [`assume_init`]), it is your responsibility
+    /// Moreover, similar to the [`ptr::read`] function, this function creates a
+    /// bitwise copy of the contents, regardless whether the contained type
+    /// implements the [`Copy`] trait or not. When using multiple copies of the
+    /// data (by calling `assume_init_read` multiple times, or first calling
+    /// `assume_init_read` and then [`assume_init`]), it is your responsibility
     /// to ensure that that data may indeed be duplicated.
     ///
     /// [inv]: #initialization-invariant
@@ -622,7 +674,8 @@ impl<T> MaybeUninit<T> {
 
     /// Drops the contained value in place.
     ///
-    /// If you have ownership of the `MaybeUninit`, you can use [`assume_init`] instead.
+    /// If you have ownership of the `MaybeUninit`, you can also use
+    /// [`assume_init`] as an alternative.
     ///
     /// # Safety
     ///
@@ -632,11 +685,12 @@ impl<T> MaybeUninit<T> {
     ///
     /// On top of that, all additional invariants of the type `T` must be
     /// satisfied, as the `Drop` implementation of `T` (or its members) may
-    /// rely on this. For example, a `1`-initialized [`Vec<T>`] is considered
-    /// initialized (under the current implementation; this does not constitute
-    /// a stable guarantee) because the only requirement the compiler knows
-    /// about it is that the data pointer must be non-null. Dropping such a
-    /// `Vec<T>` however will cause undefined behaviour.
+    /// rely on this. For example, setting a [`Vec<T>`] to an invalid but
+    /// non-null address makes it initialized (under the current implementation;
+    /// this does not constitute a stable guarantee), because the only
+    /// requirement the compiler knows about it is that the data pointer must be
+    /// non-null. Dropping such a `Vec<T>` however will cause undefined
+    /// behaviour.
     ///
     /// [`assume_init`]: MaybeUninit::assume_init
     /// [`Vec<T>`]: ../../std/vec/struct.Vec.html
diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs
index 9d9398fb56d..c26b5c67710 100644
--- a/library/core/src/ops/control_flow.rs
+++ b/library/core/src/ops/control_flow.rs
@@ -11,7 +11,6 @@ use crate::{convert, ops};
 ///
 /// Early-exiting from [`Iterator::try_for_each`]:
 /// ```
-/// #![feature(control_flow_enum)]
 /// use std::ops::ControlFlow;
 ///
 /// let r = (2..100).try_for_each(|x| {
@@ -26,7 +25,6 @@ use crate::{convert, ops};
 ///
 /// A basic tree traversal:
 /// ```no_run
-/// #![feature(control_flow_enum)]
 /// use std::ops::ControlFlow;
 ///
 /// pub struct TreeNode<T> {
@@ -48,13 +46,15 @@ use crate::{convert, ops};
 ///     }
 /// }
 /// ```
-#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
+#[stable(feature = "control_flow_enum_type", since = "1.55.0")]
 #[derive(Debug, Clone, Copy, PartialEq)]
 pub enum ControlFlow<B, C = ()> {
     /// Move on to the next phase of the operation as normal.
+    #[stable(feature = "control_flow_enum_type", since = "1.55.0")]
     #[cfg_attr(not(bootstrap), lang = "Continue")]
     Continue(C),
     /// Exit the operation without running subsequent phases.
+    #[stable(feature = "control_flow_enum_type", since = "1.55.0")]
     #[cfg_attr(not(bootstrap), lang = "Break")]
     Break(B),
     // Yes, the order of the variants doesn't match the type parameters.
diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs
index 1d9bc452618..0eec52a8701 100644
--- a/library/core/src/ops/try_trait.rs
+++ b/library/core/src/ops/try_trait.rs
@@ -55,7 +55,6 @@ use crate::ops::ControlFlow;
 /// into the return type using [`Try::from_output`]:
 /// ```
 /// # #![feature(try_trait_v2)]
-/// # #![feature(control_flow_enum)]
 /// # use std::ops::{ControlFlow, Try};
 /// fn simple_try_fold_2<A, T, R: Try<Output = A>>(
 ///     iter: impl Iterator<Item = T>,
@@ -79,7 +78,6 @@ use crate::ops::ControlFlow;
 /// recreated from their corresponding residual, so we'll just call it:
 /// ```
 /// # #![feature(try_trait_v2)]
-/// # #![feature(control_flow_enum)]
 /// # use std::ops::{ControlFlow, Try};
 /// pub fn simple_try_fold_3<A, T, R: Try<Output = A>>(
 ///     iter: impl Iterator<Item = T>,
@@ -170,7 +168,6 @@ pub trait Try: FromResidual {
     ///
     /// ```
     /// #![feature(try_trait_v2)]
-    /// #![feature(control_flow_enum)]
     /// use std::ops::Try;
     ///
     /// assert_eq!(<Result<_, String> as Try>::from_output(3), Ok(3));
@@ -202,7 +199,6 @@ pub trait Try: FromResidual {
     ///
     /// ```
     /// #![feature(try_trait_v2)]
-    /// #![feature(control_flow_enum)]
     /// use std::ops::{ControlFlow, Try};
     ///
     /// assert_eq!(Ok::<_, String>(3).branch(), ControlFlow::Continue(3));
@@ -329,7 +325,6 @@ pub trait FromResidual<R = <Self as Try>::Residual> {
     ///
     /// ```
     /// #![feature(try_trait_v2)]
-    /// #![feature(control_flow_enum)]
     /// use std::ops::{ControlFlow, FromResidual};
     ///
     /// assert_eq!(Result::<String, i64>::from_residual(Err(3_u8)), Err(3));
diff --git a/library/core/src/prelude/mod.rs b/library/core/src/prelude/mod.rs
index 79753c1fb66..ccd36a428e2 100644
--- a/library/core/src/prelude/mod.rs
+++ b/library/core/src/prelude/mod.rs
@@ -11,9 +11,9 @@ pub mod v1;
 /// The 2015 version of the core prelude.
 ///
 /// See the [module-level documentation](self) for more.
-#[unstable(feature = "prelude_2015", issue = "85684")]
+#[stable(feature = "prelude_2015", since = "1.55.0")]
 pub mod rust_2015 {
-    #[unstable(feature = "prelude_2015", issue = "85684")]
+    #[stable(feature = "prelude_2015", since = "1.55.0")]
     #[doc(no_inline)]
     pub use super::v1::*;
 }
@@ -21,9 +21,9 @@ pub mod rust_2015 {
 /// The 2018 version of the core prelude.
 ///
 /// See the [module-level documentation](self) for more.
-#[unstable(feature = "prelude_2018", issue = "85684")]
+#[stable(feature = "prelude_2018", since = "1.55.0")]
 pub mod rust_2018 {
-    #[unstable(feature = "prelude_2018", issue = "85684")]
+    #[stable(feature = "prelude_2018", since = "1.55.0")]
     #[doc(no_inline)]
     pub use super::v1::*;
 }
@@ -31,17 +31,17 @@ pub mod rust_2018 {
 /// The 2021 version of the core prelude.
 ///
 /// See the [module-level documentation](self) for more.
-#[unstable(feature = "prelude_2021", issue = "85684")]
+#[stable(feature = "prelude_2021", since = "1.55.0")]
 pub mod rust_2021 {
-    #[unstable(feature = "prelude_2021", issue = "85684")]
+    #[stable(feature = "prelude_2021", since = "1.55.0")]
     #[doc(no_inline)]
     pub use super::v1::*;
 
-    #[unstable(feature = "prelude_2021", issue = "85684")]
+    #[stable(feature = "prelude_2021", since = "1.55.0")]
     #[doc(no_inline)]
     pub use crate::iter::FromIterator;
 
-    #[unstable(feature = "prelude_2021", issue = "85684")]
+    #[stable(feature = "prelude_2021", since = "1.55.0")]
     #[doc(no_inline)]
     pub use crate::convert::{TryFrom, TryInto};
 }
diff --git a/library/core/src/time.rs b/library/core/src/time.rs
index 489b7224403..92a4e603918 100644
--- a/library/core/src/time.rs
+++ b/library/core/src/time.rs
@@ -687,21 +687,47 @@ impl Duration {
     #[inline]
     #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
     pub const fn from_secs_f64(secs: f64) -> Duration {
+        match Duration::try_from_secs_f64(secs) {
+            Ok(v) => v,
+            Err(e) => crate::panicking::panic(e.description()),
+        }
+    }
+
+    /// The checked version of [`from_secs_f64`].
+    ///
+    /// [`from_secs_f64`]: Duration::from_secs_f64
+    ///
+    /// This constructor will return an `Err` if `secs` is not finite, negative or overflows `Duration`.
+    ///
+    /// # Examples
+    /// ```
+    /// #![feature(duration_checked_float)]
+    ///
+    /// use std::time::Duration;
+    ///
+    /// let dur = Duration::try_from_secs_f64(2.7);
+    /// assert_eq!(dur, Ok(Duration::new(2, 700_000_000)));
+    ///
+    /// let negative = Duration::try_from_secs_f64(-5.0);
+    /// assert!(negative.is_err());
+    /// ```
+    #[unstable(feature = "duration_checked_float", issue = "83400")]
+    #[inline]
+    pub const fn try_from_secs_f64(secs: f64) -> Result<Duration, FromSecsError> {
         const MAX_NANOS_F64: f64 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f64;
         let nanos = secs * (NANOS_PER_SEC as f64);
         if !nanos.is_finite() {
-            panic!("got non-finite value when converting float to duration");
-        }
-        if nanos >= MAX_NANOS_F64 {
-            panic!("overflow when converting float to duration");
-        }
-        if nanos < 0.0 {
-            panic!("underflow when converting float to duration");
-        }
-        let nanos = nanos as u128;
-        Duration {
-            secs: (nanos / (NANOS_PER_SEC as u128)) as u64,
-            nanos: (nanos % (NANOS_PER_SEC as u128)) as u32,
+            Err(FromSecsError { kind: FromSecsErrorKind::NonFinite })
+        } else if nanos >= MAX_NANOS_F64 {
+            Err(FromSecsError { kind: FromSecsErrorKind::Overflow })
+        } else if nanos < 0.0 {
+            Err(FromSecsError { kind: FromSecsErrorKind::Underflow })
+        } else {
+            let nanos = nanos as u128;
+            Ok(Duration {
+                secs: (nanos / (NANOS_PER_SEC as u128)) as u64,
+                nanos: (nanos % (NANOS_PER_SEC as u128)) as u32,
+            })
         }
     }
 
@@ -722,21 +748,47 @@ impl Duration {
     #[inline]
     #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
     pub const fn from_secs_f32(secs: f32) -> Duration {
+        match Duration::try_from_secs_f32(secs) {
+            Ok(v) => v,
+            Err(e) => crate::panicking::panic(e.description()),
+        }
+    }
+
+    /// The checked version of [`from_secs_f32`].
+    ///
+    /// [`from_secs_f32`]: Duration::from_secs_f32
+    ///
+    /// This constructor will return an `Err` if `secs` is not finite, negative or overflows `Duration`.
+    ///
+    /// # Examples
+    /// ```
+    /// #![feature(duration_checked_float)]
+    ///
+    /// use std::time::Duration;
+    ///
+    /// let dur = Duration::try_from_secs_f32(2.7);
+    /// assert_eq!(dur, Ok(Duration::new(2, 700_000_000)));
+    ///
+    /// let negative = Duration::try_from_secs_f32(-5.0);
+    /// assert!(negative.is_err());
+    /// ```
+    #[unstable(feature = "duration_checked_float", issue = "83400")]
+    #[inline]
+    pub const fn try_from_secs_f32(secs: f32) -> Result<Duration, FromSecsError> {
         const MAX_NANOS_F32: f32 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f32;
         let nanos = secs * (NANOS_PER_SEC as f32);
         if !nanos.is_finite() {
-            panic!("got non-finite value when converting float to duration");
-        }
-        if nanos >= MAX_NANOS_F32 {
-            panic!("overflow when converting float to duration");
-        }
-        if nanos < 0.0 {
-            panic!("underflow when converting float to duration");
-        }
-        let nanos = nanos as u128;
-        Duration {
-            secs: (nanos / (NANOS_PER_SEC as u128)) as u64,
-            nanos: (nanos % (NANOS_PER_SEC as u128)) as u32,
+            Err(FromSecsError { kind: FromSecsErrorKind::NonFinite })
+        } else if nanos >= MAX_NANOS_F32 {
+            Err(FromSecsError { kind: FromSecsErrorKind::Overflow })
+        } else if nanos < 0.0 {
+            Err(FromSecsError { kind: FromSecsErrorKind::Underflow })
+        } else {
+            let nanos = nanos as u128;
+            Ok(Duration {
+                secs: (nanos / (NANOS_PER_SEC as u128)) as u64,
+                nanos: (nanos % (NANOS_PER_SEC as u128)) as u32,
+            })
         }
     }
 
@@ -1099,3 +1151,55 @@ impl fmt::Debug for Duration {
         }
     }
 }
+
+/// An error which can be returned when converting a floating-point value of seconds
+/// into a [`Duration`].
+///
+/// This error is used as the error type for [`Duration::try_from_secs_f32`] and
+/// [`Duration::try_from_secs_f64`].
+///
+/// # Example
+///
+/// ```
+/// #![feature(duration_checked_float)]
+///
+/// use std::time::Duration;
+///
+/// if let Err(e) = Duration::try_from_secs_f32(-1.0) {
+///     println!("Failed conversion to Duration: {}", e);
+/// }
+/// ```
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[unstable(feature = "duration_checked_float", issue = "83400")]
+pub struct FromSecsError {
+    kind: FromSecsErrorKind,
+}
+
+impl FromSecsError {
+    const fn description(&self) -> &'static str {
+        match self.kind {
+            FromSecsErrorKind::NonFinite => {
+                "got non-finite value when converting float to duration"
+            }
+            FromSecsErrorKind::Overflow => "overflow when converting float to duration",
+            FromSecsErrorKind::Underflow => "underflow when converting float to duration",
+        }
+    }
+}
+
+#[unstable(feature = "duration_checked_float", issue = "83400")]
+impl fmt::Display for FromSecsError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(self.description(), f)
+    }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+enum FromSecsErrorKind {
+    // Value is not a finite value (either infinity or NaN).
+    NonFinite,
+    // Value is too large to store in a `Duration`.
+    Overflow,
+    // Value is less than `0.0`.
+    Underflow,
+}
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 16051b3bc36..65fca67b4f2 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -15,7 +15,6 @@
 #![feature(const_ptr_read)]
 #![feature(const_ptr_write)]
 #![feature(const_ptr_offset)]
-#![feature(control_flow_enum)]
 #![feature(core_intrinsics)]
 #![feature(core_private_bignum)]
 #![feature(core_private_diy_float)]
diff --git a/library/std/src/error.rs b/library/std/src/error.rs
index 14c2f961d32..ec9f0122950 100644
--- a/library/std/src/error.rs
+++ b/library/std/src/error.rs
@@ -597,6 +597,9 @@ impl Error for char::ParseCharError {
 #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")]
 impl Error for alloc::collections::TryReserveError {}
 
+#[unstable(feature = "duration_checked_float", issue = "83400")]
+impl Error for core::time::FromSecsError {}
+
 // Copied from `any.rs`.
 impl dyn Error + 'static {
     /// Returns `true` if the boxed type is the same as `T`
diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs
index 5b8e83766f0..c2d21ad23ac 100644
--- a/library/std/src/keyword_docs.rs
+++ b/library/std/src/keyword_docs.rs
@@ -1092,8 +1092,7 @@ mod move_keyword {}
 /// Mutable raw pointers work much like mutable references, with the added
 /// possibility of not pointing to a valid object. The syntax is `*mut Type`.
 ///
-/// More information on mutable references and pointers can be found in```
-/// [Reference].
+/// More information on mutable references and pointers can be found in the [Reference].
 ///
 /// [Reference]: ../reference/types/pointer.html#mutable-references-mut
 mod mut_keyword {}
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 6f94a0599ed..6b2f49cfe48 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -261,6 +261,7 @@
 #![feature(doc_masked)]
 #![feature(doc_notable_trait)]
 #![feature(dropck_eyepatch)]
+#![feature(duration_checked_float)]
 #![feature(duration_constants)]
 #![feature(edition_panic)]
 #![feature(exact_size_is_empty)]
@@ -301,7 +302,6 @@
 #![feature(panic_internals)]
 #![feature(panic_unwind)]
 #![feature(pin_static_ref)]
-#![feature(prelude_2021)]
 #![feature(prelude_import)]
 #![feature(ptr_internals)]
 #![feature(raw)]
diff --git a/library/std/src/prelude/mod.rs b/library/std/src/prelude/mod.rs
index 12d52cc8e0b..d4bf6aeefee 100644
--- a/library/std/src/prelude/mod.rs
+++ b/library/std/src/prelude/mod.rs
@@ -25,8 +25,10 @@
 //!
 //! # Prelude contents
 //!
-//! The current version of the prelude (version 1) lives in
-//! [`std::prelude::v1`], and re-exports the following:
+//! The first version of the prelude is used in Rust 2015 and Rust 2018,
+//! and lives in [`std::prelude::v1`].
+//! [`std::prelude::rust_2015`] and [`std::prelude::rust_2018`] re-export this prelude.
+//! It re-exports the following:
 //!
 //! * <code>[std::marker]::{[Copy], [Send], [Sized], [Sync], [Unpin]}</code>,
 //!   marker traits that indicate fundamental properties of types.
@@ -58,6 +60,12 @@
 //! * <code>[std::string]::{[String], [ToString]}</code>, heap-allocated strings.
 //! * <code>[std::vec]::[Vec]</code>, a growable, heap-allocated vector.
 //!
+//! The prelude used in Rust 2021, [`std::prelude::rust_2021`], includes all of the above,
+//! and in addition re-exports:
+//!
+//! * <code>[std::convert]::{[TryFrom], [TryInto]}</code>,
+//! * <code>[std::iter]::[FromIterator]</code>.
+//!
 //! [mem::drop]: crate::mem::drop
 //! [std::borrow]: crate::borrow
 //! [std::boxed]: crate::boxed
@@ -71,10 +79,16 @@
 //! [std::ops]: crate::ops
 //! [std::option]: crate::option
 //! [`std::prelude::v1`]: v1
+//! [`std::prelude::rust_2015`]: rust_2015
+//! [`std::prelude::rust_2018`]: rust_2018
+//! [`std::prelude::rust_2021`]: rust_2021
 //! [std::result]: crate::result
 //! [std::slice]: crate::slice
 //! [std::string]: crate::string
 //! [std::vec]: mod@crate::vec
+//! [TryFrom]: crate::convert::TryFrom
+//! [TryInto]: crate::convert::TryInto
+//! [FromIterator]: crate::iter::FromIterator
 //! [`to_owned`]: crate::borrow::ToOwned::to_owned
 //! [book-closures]: ../../book/ch13-01-closures.html
 //! [book-dtor]: ../../book/ch15-03-drop.html
@@ -88,9 +102,9 @@ pub mod v1;
 /// The 2015 version of the prelude of The Rust Standard Library.
 ///
 /// See the [module-level documentation](self) for more.
-#[unstable(feature = "prelude_2015", issue = "85684")]
+#[stable(feature = "prelude_2015", since = "1.55.0")]
 pub mod rust_2015 {
-    #[unstable(feature = "prelude_2015", issue = "85684")]
+    #[stable(feature = "prelude_2015", since = "1.55.0")]
     #[doc(no_inline)]
     pub use super::v1::*;
 }
@@ -98,9 +112,9 @@ pub mod rust_2015 {
 /// The 2018 version of the prelude of The Rust Standard Library.
 ///
 /// See the [module-level documentation](self) for more.
-#[unstable(feature = "prelude_2018", issue = "85684")]
+#[stable(feature = "prelude_2018", since = "1.55.0")]
 pub mod rust_2018 {
-    #[unstable(feature = "prelude_2018", issue = "85684")]
+    #[stable(feature = "prelude_2018", since = "1.55.0")]
     #[doc(no_inline)]
     pub use super::v1::*;
 }
@@ -108,13 +122,13 @@ pub mod rust_2018 {
 /// The 2021 version of the prelude of The Rust Standard Library.
 ///
 /// See the [module-level documentation](self) for more.
-#[unstable(feature = "prelude_2021", issue = "85684")]
+#[stable(feature = "prelude_2021", since = "1.55.0")]
 pub mod rust_2021 {
-    #[unstable(feature = "prelude_2021", issue = "85684")]
+    #[stable(feature = "prelude_2021", since = "1.55.0")]
     #[doc(no_inline)]
     pub use super::v1::*;
 
-    #[unstable(feature = "prelude_2021", issue = "85684")]
+    #[stable(feature = "prelude_2021", since = "1.55.0")]
     #[doc(no_inline)]
     pub use core::prelude::rust_2021::*;
 }
diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs
index ea1d598d264..b4f4456537b 100644
--- a/library/std/src/sync/mpsc/mod.rs
+++ b/library/std/src/sync/mpsc/mod.rs
@@ -105,6 +105,35 @@
 //! });
 //! rx.recv().unwrap();
 //! ```
+//!
+//! Unbounded receive loop:
+//!
+//! ```
+//! use std::sync::mpsc::sync_channel;
+//! use std::thread;
+//!
+//! let (tx, rx) = sync_channel(3);
+//!
+//! for _ in 0..3 {
+//!     // It would be the same without thread and clone here
+//!     // since there will still be one `tx` left.
+//!     let tx = tx.clone();
+//!     // cloned tx dropped within thread
+//!     thread::spawn(move || tx.send("ok").unwrap());
+//! }
+//!
+//! // Drop the last sender to stop `rx` waiting for message.
+//! // The program will not complete if we comment this out.
+//! // **All** `tx` needs to be dropped for `rx` to have `Err`.
+//! drop(tx);
+//!
+//! // Unbounded receiver waiting for all senders to complete.
+//! while let Ok(msg) = rx.recv() {
+//!     println!("{}", msg);
+//! }
+//!
+//! println!("completed");
+//! ```
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
@@ -437,6 +466,9 @@ pub struct IntoIter<T> {
 ///
 /// Messages can be sent through this channel with [`send`].
 ///
+/// Note: all senders (the original and the clones) need to be dropped for the receiver
+/// to stop blocking to receive messages with [`Receiver::recv`].
+///
 /// [`send`]: Sender::send
 ///
 /// # Examples
@@ -643,7 +675,7 @@ impl<T> UnsafeFlavor<T> for Receiver<T> {
 /// the same order as it was sent, and no [`send`] will block the calling thread
 /// (this channel has an "infinite buffer", unlike [`sync_channel`], which will
 /// block after its buffer limit is reached). [`recv`] will block until a message
-/// is available.
+/// is available while there is at least one [`Sender`] alive (including clones).
 ///
 /// The [`Sender`] can be cloned to [`send`] to the same channel multiple times, but
 /// only one [`Receiver`] is supported.
@@ -806,6 +838,11 @@ impl<T> Sender<T> {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> Clone for Sender<T> {
+    /// Clone a sender to send to other threads.
+    ///
+    /// Note, be aware of the lifetime of the sender because all senders
+    /// (including the original) need to be dropped in order for
+    /// [`Receiver::recv`] to stop blocking.
     fn clone(&self) -> Sender<T> {
         let packet = match *unsafe { self.inner() } {
             Flavor::Oneshot(ref p) => {
@@ -1064,9 +1101,10 @@ impl<T> Receiver<T> {
     /// corresponding channel has hung up.
     ///
     /// This function will always block the current thread if there is no data
-    /// available and it's possible for more data to be sent. Once a message is
-    /// sent to the corresponding [`Sender`] (or [`SyncSender`]), then this
-    /// receiver will wake up and return that message.
+    /// available and it's possible for more data to be sent (at least one sender
+    /// still exists). Once a message is sent to the corresponding [`Sender`]
+    /// (or [`SyncSender`]), this receiver will wake up and return that
+    /// message.
     ///
     /// If the corresponding [`Sender`] has disconnected, or it disconnects while
     /// this call is blocking, this call will wake up and return [`Err`] to
@@ -1146,9 +1184,10 @@ impl<T> Receiver<T> {
     /// corresponding channel has hung up, or if it waits more than `timeout`.
     ///
     /// This function will always block the current thread if there is no data
-    /// available and it's possible for more data to be sent. Once a message is
-    /// sent to the corresponding [`Sender`] (or [`SyncSender`]), then this
-    /// receiver will wake up and return that message.
+    /// available and it's possible for more data to be sent (at least one sender
+    /// still exists). Once a message is sent to the corresponding [`Sender`]
+    /// (or [`SyncSender`]), this receiver will wake up and return that
+    /// message.
     ///
     /// If the corresponding [`Sender`] has disconnected, or it disconnects while
     /// this call is blocking, this call will wake up and return [`Err`] to
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index b7efc884473..b64870401f1 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -234,6 +234,7 @@ pub const SD_RECEIVE: c_int = 0;
 pub const SD_SEND: c_int = 1;
 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_RCVTIMEO: c_int = 0x1006;
 pub const SO_SNDTIMEO: c_int = 0x1005;
diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs
index 1ad13254c08..9cea5c5e63a 100644
--- a/library/std/src/sys/windows/net.rs
+++ b/library/std/src/sys/windows/net.rs
@@ -12,7 +12,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, c_void};
+use libc::{c_int, c_long, c_ulong};
 
 pub type wrlen_t = i32;
 
@@ -93,153 +93,177 @@ where
 
 impl Socket {
     pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> {
-        let fam = match *addr {
+        let family = match *addr {
             SocketAddr::V4(..) => c::AF_INET,
             SocketAddr::V6(..) => c::AF_INET6,
         };
         let socket = unsafe {
-            match c::WSASocketW(
-                fam,
+            c::WSASocketW(
+                family,
                 ty,
                 0,
                 ptr::null_mut(),
                 0,
                 c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT,
-            ) {
-                c::INVALID_SOCKET => match c::WSAGetLastError() {
-                    c::WSAEPROTOTYPE | c::WSAEINVAL => {
-                        match c::WSASocketW(fam, ty, 0, ptr::null_mut(), 0, c::WSA_FLAG_OVERLAPPED)
-                        {
-                            c::INVALID_SOCKET => Err(last_error()),
-                            n => {
-                                let s = Socket(n);
-                                s.set_no_inherit()?;
-                                Ok(s)
-                            }
-                        }
-                    }
-                    n => Err(io::Error::from_raw_os_error(n)),
-                },
-                n => Ok(Socket(n)),
+            )
+        };
+
+        if socket != c::INVALID_SOCKET {
+            Ok(Self(socket))
+        } else {
+            let error = unsafe { c::WSAGetLastError() };
+
+            if error != c::WSAEPROTOTYPE && error != c::WSAEINVAL {
+                return Err(io::Error::from_raw_os_error(error));
+            }
+
+            let socket =
+                unsafe { c::WSASocketW(family, ty, 0, ptr::null_mut(), 0, c::WSA_FLAG_OVERLAPPED) };
+
+            if socket == c::INVALID_SOCKET {
+                return Err(last_error());
             }
-        }?;
-        Ok(socket)
+
+            let socket = Self(socket);
+            socket.set_no_inherit()?;
+            Ok(socket)
+        }
     }
 
     pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
         self.set_nonblocking(true)?;
-        let r = unsafe {
+        let result = {
             let (addrp, len) = addr.into_inner();
-            cvt(c::connect(self.0, addrp, len))
+            let result = unsafe { c::connect(self.0, addrp, len) };
+            cvt(result).map(drop)
         };
         self.set_nonblocking(false)?;
 
-        match r {
-            Ok(_) => return Ok(()),
-            Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {}
-            Err(e) => return Err(e),
-        }
-
-        if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
-            return Err(io::Error::new_const(
-                io::ErrorKind::InvalidInput,
-                &"cannot set a 0 duration timeout",
-            ));
-        }
-
-        let mut timeout = c::timeval {
-            tv_sec: timeout.as_secs() as c_long,
-            tv_usec: (timeout.subsec_nanos() / 1000) as c_long,
-        };
-        if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
-            timeout.tv_usec = 1;
-        }
+        match result {
+            Err(ref error) if error.kind() == io::ErrorKind::WouldBlock => {
+                if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
+                    return Err(io::Error::new_const(
+                        io::ErrorKind::InvalidInput,
+                        &"cannot set a 0 duration timeout",
+                    ));
+                }
 
-        let fds = unsafe {
-            let mut fds = mem::zeroed::<c::fd_set>();
-            fds.fd_count = 1;
-            fds.fd_array[0] = self.0;
-            fds
-        };
+                let mut timeout = c::timeval {
+                    tv_sec: timeout.as_secs() as c_long,
+                    tv_usec: (timeout.subsec_nanos() / 1000) as c_long,
+                };
 
-        let mut writefds = fds;
-        let mut errorfds = fds;
+                if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
+                    timeout.tv_usec = 1;
+                }
 
-        let n =
-            unsafe { cvt(c::select(1, ptr::null_mut(), &mut writefds, &mut errorfds, &timeout))? };
+                let fds = {
+                    let mut fds = unsafe { mem::zeroed::<c::fd_set>() };
+                    fds.fd_count = 1;
+                    fds.fd_array[0] = self.0;
+                    fds
+                };
+
+                let mut writefds = fds;
+                let mut errorfds = fds;
+
+                let count = {
+                    let result = unsafe {
+                        c::select(1, ptr::null_mut(), &mut writefds, &mut errorfds, &timeout)
+                    };
+                    cvt(result)?
+                };
+
+                match count {
+                    0 => {
+                        Err(io::Error::new_const(io::ErrorKind::TimedOut, &"connection timed out"))
+                    }
+                    _ => {
+                        if writefds.fd_count != 1 {
+                            if let Some(e) = self.take_error()? {
+                                return Err(e);
+                            }
+                        }
 
-        match n {
-            0 => Err(io::Error::new_const(io::ErrorKind::TimedOut, &"connection timed out")),
-            _ => {
-                if writefds.fd_count != 1 {
-                    if let Some(e) = self.take_error()? {
-                        return Err(e);
+                        Ok(())
                     }
                 }
-                Ok(())
             }
+            _ => result,
         }
     }
 
     pub fn accept(&self, storage: *mut c::SOCKADDR, len: *mut c_int) -> io::Result<Socket> {
-        let socket = unsafe {
-            match c::accept(self.0, storage, len) {
-                c::INVALID_SOCKET => Err(last_error()),
-                n => Ok(Socket(n)),
-            }
-        }?;
-        Ok(socket)
+        let socket = unsafe { c::accept(self.0, storage, len) };
+
+        match socket {
+            c::INVALID_SOCKET => Err(last_error()),
+            _ => Ok(Self(socket)),
+        }
     }
 
     pub fn duplicate(&self) -> io::Result<Socket> {
+        let mut info = unsafe { mem::zeroed::<c::WSAPROTOCOL_INFO>() };
+        let result = unsafe { c::WSADuplicateSocketW(self.0, c::GetCurrentProcessId(), &mut info) };
+        cvt(result)?;
         let socket = unsafe {
-            let mut info: c::WSAPROTOCOL_INFO = mem::zeroed();
-            cvt(c::WSADuplicateSocketW(self.0, c::GetCurrentProcessId(), &mut info))?;
-
-            match c::WSASocketW(
+            c::WSASocketW(
                 info.iAddressFamily,
                 info.iSocketType,
                 info.iProtocol,
                 &mut info,
                 0,
                 c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT,
-            ) {
-                c::INVALID_SOCKET => match c::WSAGetLastError() {
-                    c::WSAEPROTOTYPE | c::WSAEINVAL => {
-                        match c::WSASocketW(
-                            info.iAddressFamily,
-                            info.iSocketType,
-                            info.iProtocol,
-                            &mut info,
-                            0,
-                            c::WSA_FLAG_OVERLAPPED,
-                        ) {
-                            c::INVALID_SOCKET => Err(last_error()),
-                            n => {
-                                let s = Socket(n);
-                                s.set_no_inherit()?;
-                                Ok(s)
-                            }
-                        }
-                    }
-                    n => Err(io::Error::from_raw_os_error(n)),
-                },
-                n => Ok(Socket(n)),
+            )
+        };
+
+        if socket != c::INVALID_SOCKET {
+            Ok(Self(socket))
+        } else {
+            let error = unsafe { c::WSAGetLastError() };
+
+            if error != c::WSAEPROTOTYPE && error != c::WSAEINVAL {
+                return Err(io::Error::from_raw_os_error(error));
+            }
+
+            let socket = unsafe {
+                c::WSASocketW(
+                    info.iAddressFamily,
+                    info.iSocketType,
+                    info.iProtocol,
+                    &mut info,
+                    0,
+                    c::WSA_FLAG_OVERLAPPED,
+                )
+            };
+
+            if socket == c::INVALID_SOCKET {
+                return Err(last_error());
             }
-        }?;
-        Ok(socket)
+
+            let socket = Self(socket);
+            socket.set_no_inherit()?;
+            Ok(socket)
+        }
     }
 
     fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> {
         // On unix when a socket is shut down all further reads return 0, so we
         // do the same on windows to map a shut down socket to returning EOF.
-        let len = cmp::min(buf.len(), i32::MAX as usize) as i32;
-        unsafe {
-            match c::recv(self.0, buf.as_mut_ptr() as *mut c_void, len, flags) {
-                -1 if c::WSAGetLastError() == c::WSAESHUTDOWN => Ok(0),
-                -1 => Err(last_error()),
-                n => Ok(n as usize),
+        let length = cmp::min(buf.len(), i32::MAX as usize) as i32;
+        let result = unsafe { c::recv(self.0, buf.as_mut_ptr() as *mut _, length, flags) };
+
+        match result {
+            c::SOCKET_ERROR => {
+                let error = unsafe { c::WSAGetLastError() };
+
+                if error == c::WSAESHUTDOWN {
+                    Ok(0)
+                } else {
+                    Err(io::Error::from_raw_os_error(error))
+                }
             }
+            _ => Ok(result as usize),
         }
     }
 
@@ -250,23 +274,31 @@ impl Socket {
     pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
         // On unix when a socket is shut down all further reads return 0, so we
         // do the same on windows to map a shut down socket to returning EOF.
-        let len = cmp::min(bufs.len(), c::DWORD::MAX as usize) as c::DWORD;
+        let length = cmp::min(bufs.len(), c::DWORD::MAX as usize) as c::DWORD;
         let mut nread = 0;
         let mut flags = 0;
-        unsafe {
-            let ret = c::WSARecv(
+        let result = unsafe {
+            c::WSARecv(
                 self.0,
                 bufs.as_mut_ptr() as *mut c::WSABUF,
-                len,
+                length,
                 &mut nread,
                 &mut flags,
                 ptr::null_mut(),
                 ptr::null_mut(),
-            );
-            match ret {
-                0 => Ok(nread as usize),
-                _ if c::WSAGetLastError() == c::WSAESHUTDOWN => Ok(0),
-                _ => Err(last_error()),
+            )
+        };
+
+        match result {
+            0 => Ok(nread as usize),
+            _ => {
+                let error = unsafe { c::WSAGetLastError() };
+
+                if error == c::WSAESHUTDOWN {
+                    Ok(0)
+                } else {
+                    Err(io::Error::from_raw_os_error(error))
+                }
             }
         }
     }
@@ -285,27 +317,34 @@ impl Socket {
         buf: &mut [u8],
         flags: c_int,
     ) -> io::Result<(usize, SocketAddr)> {
-        let mut storage: c::SOCKADDR_STORAGE_LH = unsafe { mem::zeroed() };
+        let mut storage = unsafe { mem::zeroed::<c::SOCKADDR_STORAGE_LH>() };
         let mut addrlen = mem::size_of_val(&storage) as c::socklen_t;
-        let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t;
+        let length = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t;
 
         // On unix when a socket is shut down all further reads return 0, so we
         // do the same on windows to map a shut down socket to returning EOF.
-        unsafe {
-            match c::recvfrom(
+        let result = unsafe {
+            c::recvfrom(
                 self.0,
-                buf.as_mut_ptr() as *mut c_void,
-                len,
+                buf.as_mut_ptr() as *mut _,
+                length,
                 flags,
                 &mut storage as *mut _ as *mut _,
                 &mut addrlen,
-            ) {
-                -1 if c::WSAGetLastError() == c::WSAESHUTDOWN => {
+            )
+        };
+
+        match result {
+            c::SOCKET_ERROR => {
+                let error = unsafe { c::WSAGetLastError() };
+
+                if error == c::WSAESHUTDOWN {
                     Ok((0, net::sockaddr_to_addr(&storage, addrlen as usize)?))
+                } else {
+                    Err(io::Error::from_raw_os_error(error))
                 }
-                -1 => Err(last_error()),
-                n => Ok((n as usize, net::sockaddr_to_addr(&storage, addrlen as usize)?)),
             }
+            _ => Ok((result as usize, net::sockaddr_to_addr(&storage, addrlen as usize)?)),
         }
     }
 
@@ -318,20 +357,20 @@ impl Socket {
     }
 
     pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        let len = cmp::min(bufs.len(), c::DWORD::MAX as usize) as c::DWORD;
+        let length = cmp::min(bufs.len(), c::DWORD::MAX as usize) as c::DWORD;
         let mut nwritten = 0;
-        unsafe {
-            cvt(c::WSASend(
+        let result = unsafe {
+            c::WSASend(
                 self.0,
-                bufs.as_ptr() as *const c::WSABUF as *mut c::WSABUF,
-                len,
+                bufs.as_ptr() as *const c::WSABUF as *mut _,
+                length,
                 &mut nwritten,
                 0,
                 ptr::null_mut(),
                 ptr::null_mut(),
-            ))?;
-        }
-        Ok(nwritten as usize)
+            )
+        };
+        cvt(result).map(|_| nwritten as usize)
     }
 
     #[inline]
@@ -384,14 +423,14 @@ impl Socket {
             Shutdown::Read => c::SD_RECEIVE,
             Shutdown::Both => c::SD_BOTH,
         };
-        cvt(unsafe { c::shutdown(self.0, how) })?;
-        Ok(())
+        let result = unsafe { c::shutdown(self.0, how) };
+        cvt(result).map(drop)
     }
 
     pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
         let mut nonblocking = nonblocking as c_ulong;
-        let r = unsafe { c::ioctlsocket(self.0, c::FIONBIO as c_int, &mut nonblocking) };
-        if r == 0 { Ok(()) } else { Err(io::Error::last_os_error()) }
+        let result = unsafe { c::ioctlsocket(self.0, c::FIONBIO as c_int, &mut nonblocking) };
+        cvt(result).map(drop)
     }
 
     pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index ebb4cfb7d48..46fe3e2408f 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -965,14 +965,8 @@ fn render_assoc_item(
     }
 }
 
-const ALLOWED_ATTRIBUTES: &[Symbol] = &[
-    sym::export_name,
-    sym::link_section,
-    sym::must_use,
-    sym::no_mangle,
-    sym::repr,
-    sym::non_exhaustive,
-];
+const ALLOWED_ATTRIBUTES: &[Symbol] =
+    &[sym::export_name, sym::link_section, sym::no_mangle, sym::repr, sym::non_exhaustive];
 
 fn attributes(it: &clean::Item) -> Vec<String> {
     it.attrs
diff --git a/src/test/rustdoc/attributes.rs b/src/test/rustdoc/attributes.rs
index 51cd4a6cbfd..6a588fbd56e 100644
--- a/src/test/rustdoc/attributes.rs
+++ b/src/test/rustdoc/attributes.rs
@@ -8,14 +8,6 @@ pub extern "C" fn f() {}
 #[export_name = "bar"]
 pub extern "C" fn g() {}
 
-// @matches foo/enum.Foo.html '//*[@class="rust enum"]' \
-//      '#\[repr\(i64\)\]\n#\[must_use\]'
-#[repr(i64)]
-#[must_use]
-pub enum Foo {
-    Bar,
-}
-
 // @has foo/struct.Repr.html '//*[@class="docblock type-decl"]' '#[repr(C, align(8))]'
 #[repr(C, align(8))]
 pub struct Repr;
diff --git a/src/test/rustdoc/cap-lints.rs b/src/test/rustdoc/cap-lints.rs
index b66f75695f2..15910e1e900 100644
--- a/src/test/rustdoc/cap-lints.rs
+++ b/src/test/rustdoc/cap-lints.rs
@@ -3,8 +3,7 @@
 // therefore should not concern itself with the lints.
 #[deny(warnings)]
 
-// @has cap_lints/struct.Foo.html //pre '#[must_use]'
-#[must_use]
+// @has cap_lints/struct.Foo.html //* 'Struct Foo'
 pub struct Foo {
     field: i32,
 }
diff --git a/src/test/rustdoc/must-use.rs b/src/test/rustdoc/must-use.rs
deleted file mode 100644
index b52557fe220..00000000000
--- a/src/test/rustdoc/must-use.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-// @has must_use/struct.Struct.html //pre '#[must_use]'
-#[must_use]
-pub struct Struct {
-    field: i32,
-}
-
-// @has must_use/enum.Enum.html //pre '#[must_use = "message"]'
-#[must_use = "message"]
-pub enum Enum {
-    Variant(i32),
-}
diff --git a/src/test/rustdoc/trait-attributes.rs b/src/test/rustdoc/trait-attributes.rs
deleted file mode 100644
index d0dfb8759e6..00000000000
--- a/src/test/rustdoc/trait-attributes.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-#![crate_name = "foo"]
-
-
-pub trait Foo {
-    // @has foo/trait.Foo.html '//div[@id="tymethod.foo"]//div[@class="code-attribute"]' '#[must_use]'
-    #[must_use]
-    fn foo();
-}
-
-#[must_use]
-pub struct Bar;
-
-impl Bar {
-    // @has foo/struct.Bar.html '//div[@id="method.bar"]//div[@class="code-attribute"]' '#[must_use]'
-    #[must_use]
-    pub fn bar() {}
-
-    // @has foo/struct.Bar.html '//div[@id="method.bar2"]//div[@class="code-attribute"]' '#[must_use]'
-    #[must_use]
-    pub fn bar2() {}
-}
diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer
-Subproject 13da28cc2bc1b59f7af817eca36927a71edb023
+Subproject f0618a8f06a464840079f30b3e25bcdcca3922a