From 65a0a8b38663751870264fb73815c5586f324b47 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 23 May 2021 10:21:25 -0700 Subject: [PATCH 01/12] Stabilize ops::ControlFlow (just the type) --- compiler/rustc_ast_lowering/src/lib.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 1 - compiler/rustc_span/src/symbol.rs | 1 - compiler/rustc_traits/src/lib.rs | 1 - library/core/src/iter/traits/iterator.rs | 41 ++++++++++++++++++++++++ library/core/src/ops/control_flow.rs | 6 ++-- library/core/src/ops/try_trait.rs | 5 --- library/core/tests/lib.rs | 1 - 8 files changed, 45 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 56f97054f9624..7e1761ea868cf 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -332,7 +332,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 300d2c01cb5d0..b1dd942719820 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 14ee083eceebe..8b682d068c071 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -414,7 +414,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 7b688cd3e2199..d0b05beb4e63c 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 777e4bc2c8920..922133fa6994f 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1993,6 +1993,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(&mut self, init: B, mut f: F) -> R @@ -2035,6 +2060,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(&mut self, f: F) -> R diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index dbb51540bd475..4a7da1c3cac99 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 { @@ -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.54.0")] #[derive(Debug, Clone, Copy, PartialEq)] pub enum ControlFlow { /// Move on to the next phase of the operation as normal. + #[stable(feature = "control_flow_enum_type", since = "1.54.0")] #[cfg_attr(not(bootstrap), lang = "Continue")] Continue(C), /// Exit the operation without running subsequent phases. + #[stable(feature = "control_flow_enum_type", since = "1.54.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 87044ed2fcee1..8628db13ed5fb 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>( /// iter: impl Iterator, @@ -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>( /// iter: impl Iterator, @@ -170,7 +168,6 @@ pub trait Try: FromResidual { /// /// ``` /// #![feature(try_trait_v2)] - /// #![feature(control_flow_enum)] /// use std::ops::Try; /// /// assert_eq!( 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)); @@ -304,7 +300,6 @@ pub trait FromResidual::Residual> { /// /// ``` /// #![feature(try_trait_v2)] - /// #![feature(control_flow_enum)] /// use std::ops::{ControlFlow, FromResidual}; /// /// assert_eq!(Result::::from_residual(Err(3_u8)), Err(3)); diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index db12d79c00c30..4cc2765dc7d95 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)] From 78d3d3790a56227ba915d559907f5e6db54640db Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 28 May 2021 20:32:42 +0100 Subject: [PATCH 02/12] Refactor windows sockets impl methods --- library/std/src/sys/windows/c.rs | 1 + library/std/src/sys/windows/net.rs | 305 ++++++++++++++++------------- 2 files changed, 173 insertions(+), 133 deletions(-) diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index b7efc884473b4..b64870401f1fd 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 1ad13254c0846..9cea5c5e63a2d 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 { - 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::(); - 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::() }; + 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 { - 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 { + let mut info = unsafe { mem::zeroed::() }; + 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 { // 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 { // 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::() }; let mut addrlen = mem::size_of_val(&storage) as c::socklen_t; - let len = cmp::min(buf.len(), ::MAX as usize) as wrlen_t; + let length = cmp::min(buf.len(), ::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 { - 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<()> { From 0f3c7d18fb1213ad285173210820924b76b534a1 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Tue, 22 Dec 2020 02:16:01 +0800 Subject: [PATCH 03/12] Explain non-dropped sender recv in docs Original senders that are still hanging around could cause Receiver::recv to not block since this is a potential footgun for beginners, clarify more on this in the docs for readers to be aware about it. Fix minor tidbits in sender recv doc Co-authored-by: Dylan DPC Add example for unbounded receive loops in doc Show the drop(tx) pattern, based on tokio docs https://tokio-rs.github.io/tokio/doc/tokio/sync/index.html Fix example code for drop sender recv Fix wording in sender docs Co-authored-by: Josh Triplett --- library/std/src/sync/mpsc/mod.rs | 53 +++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs index db0777ee9f080..0465a19a47817 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")] @@ -436,6 +465,9 @@ pub struct IntoIter { /// /// 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 @@ -642,7 +674,7 @@ impl UnsafeFlavor for Receiver { /// 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. @@ -805,6 +837,11 @@ impl Sender { #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Sender { + /// 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 { let packet = match *unsafe { self.inner() } { Flavor::Oneshot(ref p) => { @@ -1063,9 +1100,10 @@ impl Receiver { /// 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 @@ -1145,9 +1183,10 @@ impl Receiver { /// 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 From 74e8e7bb600212e7fef9782fde5ad9c13e1d65a0 Mon Sep 17 00:00:00 2001 From: Jacob Hoffman-Andrews Date: Sun, 13 Jun 2021 15:38:44 -0700 Subject: [PATCH 04/12] Remove must_use from ALLOWED_ATTRIBUTES This is a fairly common attribute on methods, but is not something you need to know when reading the method docs - the purpose of the attribute is for the compiler to tell you about it if you forget to use a value. Removing reclaims some valuable space in the summary of methods. --- src/librustdoc/html/render/mod.rs | 10 ++-------- src/test/rustdoc/attributes.rs | 8 -------- src/test/rustdoc/cap-lints.rs | 3 +-- src/test/rustdoc/must-use.rs | 11 ----------- src/test/rustdoc/trait-attributes.rs | 21 --------------------- 5 files changed, 3 insertions(+), 50 deletions(-) delete mode 100644 src/test/rustdoc/must-use.rs delete mode 100644 src/test/rustdoc/trait-attributes.rs diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 2e940a31c2aff..cd39393d03b47 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 { it.attrs diff --git a/src/test/rustdoc/attributes.rs b/src/test/rustdoc/attributes.rs index 51cd4a6cbfd12..6a588fbd56e75 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 b66f75695f2ab..15910e1e9006d 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 b52557fe220ee..0000000000000 --- 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 d0dfb8759e665..0000000000000 --- 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() {} -} From 69f88f55c5f4bae17cf8356490682484d852c2f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Mon, 14 Jun 2021 09:44:02 +0300 Subject: [PATCH 05/12] :arrow_up: rust-analyzer --- src/tools/rust-analyzer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer index 13da28cc2bc1b..f0618a8f06a46 160000 --- a/src/tools/rust-analyzer +++ b/src/tools/rust-analyzer @@ -1 +1 @@ -Subproject commit 13da28cc2bc1b59f7af817eca36927a71edb023c +Subproject commit f0618a8f06a464840079f30b3e25bcdcca3922a3 From 87102587149ce00d008c3463bf6283f5145b2f23 Mon Sep 17 00:00:00 2001 From: est31 Date: Fri, 11 Jun 2021 15:38:48 +0200 Subject: [PATCH 06/12] Improve maybe_uninit_extra docs For reasoning, see https://github.com/rust-lang/rust/issues/63567#issuecomment-858640987 --- library/core/src/mem/maybe_uninit.rs | 80 +++++++++++++++++++++++----- 1 file changed, 67 insertions(+), 13 deletions(-) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 10219201a40d3..1f06bd0012c60 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -402,10 +402,60 @@ impl MaybeUninit { u } - /// Sets the value of the `MaybeUninit`. 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`. + /// + /// 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::>::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::::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 MaybeUninit { /// 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`. 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 MaybeUninit { /// 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 MaybeUninit { /// /// 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`] 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` however will cause undefined behaviour. + /// rely on this. For example, setting a [`Vec`] 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` however will cause undefined + /// behaviour. /// /// [`assume_init`]: MaybeUninit::assume_init /// [`Vec`]: ../../std/vec/struct.Vec.html From c2c1ca071f242c3e84775bba2a05a6c924f44b1e Mon Sep 17 00:00:00 2001 From: mbartlett21 <29034492+mbartlett21@users.noreply.github.com> Date: Mon, 14 Jun 2021 12:16:13 +0000 Subject: [PATCH 07/12] Add functions `Duration::try_from_secs_{f32, f64}` This also adds the error type used, `FromSecsError` and its `impl`s. --- library/core/src/time.rs | 128 +++++++++++++++++++++++++++++++++++++++ library/std/src/error.rs | 3 + library/std/src/lib.rs | 1 + 3 files changed, 132 insertions(+) diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 88b4e2a2436e7..22e8e14398622 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -697,6 +697,44 @@ impl Duration { } } + /// 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 { + 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() { + 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, + }) + } + } + /// Creates a new `Duration` from the specified number of seconds represented /// as `f32`. /// @@ -732,6 +770,44 @@ impl Duration { } } + /// 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 { + 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() { + 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, + }) + } + } + /// Multiplies `Duration` by `f64`. /// /// # Panics @@ -1081,3 +1157,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/std/src/error.rs b/library/std/src/error.rs index ca83c409822fc..c16660ef92c23 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -529,6 +529,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/lib.rs b/library/std/src/lib.rs index 5ba13c2f91334..a42d88ef71427 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -256,6 +256,7 @@ #![feature(doc_masked)] #![feature(doc_spotlight)] #![feature(dropck_eyepatch)] +#![feature(duration_checked_float)] #![feature(duration_constants)] #![feature(duration_zero)] #![feature(exact_size_is_empty)] From 7803955cae3dffb37c315e95764df8e949eea590 Mon Sep 17 00:00:00 2001 From: mbartlett21 <29034492+mbartlett21@users.noreply.github.com> Date: Mon, 14 Jun 2021 12:17:53 +0000 Subject: [PATCH 08/12] Use `try_from_secs_*` in `Duration::from_secs_*` functions. `Duration::from_secs_{f32, f64}` now use the results from the non-panicking functions and unwrap it. --- library/core/src/time.rs | 36 ++++++------------------------------ 1 file changed, 6 insertions(+), 30 deletions(-) diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 22e8e14398622..cc37000bb14ce 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -679,21 +679,9 @@ impl Duration { #[inline] #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] pub const fn from_secs_f64(secs: f64) -> Duration { - 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, + match Duration::try_from_secs_f64(secs) { + Ok(v) => v, + Err(e) => crate::panicking::panic(e.description()), } } @@ -752,21 +740,9 @@ impl Duration { #[inline] #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] pub const fn from_secs_f32(secs: f32) -> Duration { - 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, + match Duration::try_from_secs_f32(secs) { + Ok(v) => v, + Err(e) => crate::panicking::panic(e.description()), } } From 65c1d3597309063635f2d846db6ebab334492eb2 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 14 Jun 2021 14:44:50 +0000 Subject: [PATCH 09/12] Stabilize {std, core}::prelude::rust_*. --- library/core/src/prelude/mod.rs | 16 ++++++++-------- library/std/src/lib.rs | 1 - library/std/src/prelude/mod.rs | 32 +++++++++++++++++++++++--------- 3 files changed, 31 insertions(+), 18 deletions(-) diff --git a/library/core/src/prelude/mod.rs b/library/core/src/prelude/mod.rs index 79753c1fb6687..ccd36a428e296 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/std/src/lib.rs b/library/std/src/lib.rs index c4f21587457c1..b4b94405dfc28 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -302,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 12d52cc8e0b22..d4bf6aeefee57 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: //! //! * [std::marker]::{[Copy], [Send], [Sized], [Sync], [Unpin]}, //! marker traits that indicate fundamental properties of types. @@ -58,6 +60,12 @@ //! * [std::string]::{[String], [ToString]}, heap-allocated strings. //! * [std::vec]::[Vec], 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: +//! +//! * [std::convert]::{[TryFrom], [TryInto]}, +//! * [std::iter]::[FromIterator]. +//! //! [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::*; } From 590d4526e91d77cc514deb58c3d87e30b3f74db6 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Mon, 14 Jun 2021 10:37:05 -0700 Subject: [PATCH 10/12] Master is 1.55 now :( --- library/core/src/ops/control_flow.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index 4a7da1c3cac99..ff1e968a8d113 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -46,15 +46,15 @@ use crate::{convert, ops}; /// } /// } /// ``` -#[stable(feature = "control_flow_enum_type", since = "1.54.0")] +#[stable(feature = "control_flow_enum_type", since = "1.55.0")] #[derive(Debug, Clone, Copy, PartialEq)] pub enum ControlFlow { /// Move on to the next phase of the operation as normal. - #[stable(feature = "control_flow_enum_type", since = "1.54.0")] + #[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.54.0")] + #[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. From 91b0553fcdb5a5854498bd1049969a1efaccd78d Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Thu, 27 May 2021 23:35:31 +0200 Subject: [PATCH 11/12] Add mailmap entries for myself --- .mailmap | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.mailmap b/.mailmap index 213aa6eff6666..8cb74824d939a 100644 --- a/.mailmap +++ b/.mailmap @@ -166,6 +166,8 @@ lcnr Lee Jeffery Lee Jeffery Lee Wondong Lennart Kudling +Léo Lanteri Thauvin +Léo Lanteri Thauvin <38361244+LeSeulArtichaut@users.noreply.github.com> Léo Testard Lindsey Kuper Lindsey Kuper From 7cd750f16f024e807efb992dc55f7ceeb91c8925 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 15 Jun 2021 00:22:03 +0200 Subject: [PATCH 12/12] Update keyword_docs.rs --- library/std/src/keyword_docs.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index 5b8e83766f0e8..c2d21ad23ac19 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 {}