mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-15 20:45:45 +03:00
Rollup merge of #60373 - rasendubi:lang-features-sort-since, r=Centril
Tidy: ensure lang features are sorted by since This is the tidy side of https://github.com/rust-lang/rust/issues/60361. What is left is actually splitting features into groups and sorting by since. This PR also likely to produce a small (a couple of lines) merge conflict with https://github.com/rust-lang/rust/pull/60362. r? @Centril
This commit is contained in:
@@ -3556,6 +3556,7 @@ dependencies = [
|
||||
name = "tidy"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#![stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#![stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
|
||||
//! Unix-specific networking functionality
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
/// let addr = socket.local_addr().expect("Couldn't get local address");
|
||||
/// ```
|
||||
#[derive(Clone)]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
pub struct SocketAddr(());
|
||||
|
||||
impl SocketAddr {
|
||||
@@ -55,7 +55,7 @@ impl SocketAddr {
|
||||
/// let addr = socket.local_addr().expect("Couldn't get local address");
|
||||
/// assert_eq!(addr.as_pathname(), None);
|
||||
/// ```
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
pub fn as_pathname(&self) -> Option<&Path> {
|
||||
None
|
||||
}
|
||||
@@ -83,12 +83,12 @@ pub fn as_pathname(&self) -> Option<&Path> {
|
||||
/// let addr = socket.local_addr().expect("Couldn't get local address");
|
||||
/// assert_eq!(addr.is_unnamed(), true);
|
||||
/// ```
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
pub fn is_unnamed(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
impl fmt::Debug for SocketAddr {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(fmt, "SocketAddr")
|
||||
@@ -109,10 +109,10 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
/// stream.read_to_string(&mut response).unwrap();
|
||||
/// println!("{}", response);
|
||||
/// ```
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
pub struct UnixStream(FileDesc);
|
||||
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
impl fmt::Debug for UnixStream {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let mut builder = fmt.debug_struct("UnixStream");
|
||||
@@ -143,7 +143,7 @@ impl UnixStream {
|
||||
/// }
|
||||
/// };
|
||||
/// ```
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
pub fn connect<P: AsRef<Path>>(path: P) -> io::Result<UnixStream> {
|
||||
if let Some(s) = path.as_ref().to_str() {
|
||||
cvt(syscall::open(format!("chan:{}", s), syscall::O_CLOEXEC))
|
||||
@@ -174,7 +174,7 @@ pub fn connect<P: AsRef<Path>>(path: P) -> io::Result<UnixStream> {
|
||||
/// }
|
||||
/// };
|
||||
/// ```
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
pub fn pair() -> io::Result<(UnixStream, UnixStream)> {
|
||||
let server = cvt(syscall::open("chan:", syscall::O_CREAT | syscall::O_CLOEXEC))
|
||||
.map(FileDesc::new)?;
|
||||
@@ -198,7 +198,7 @@ pub fn pair() -> io::Result<(UnixStream, UnixStream)> {
|
||||
/// let socket = UnixStream::connect("/tmp/sock").unwrap();
|
||||
/// let sock_copy = socket.try_clone().expect("Couldn't clone socket");
|
||||
/// ```
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
pub fn try_clone(&self) -> io::Result<UnixStream> {
|
||||
self.0.duplicate().map(UnixStream)
|
||||
}
|
||||
@@ -213,7 +213,7 @@ pub fn try_clone(&self) -> io::Result<UnixStream> {
|
||||
/// let socket = UnixStream::connect("/tmp/sock").unwrap();
|
||||
/// let addr = socket.local_addr().expect("Couldn't get local address");
|
||||
/// ```
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
pub fn local_addr(&self) -> io::Result<SocketAddr> {
|
||||
Err(Error::new(ErrorKind::Other, "UnixStream::local_addr unimplemented on redox"))
|
||||
}
|
||||
@@ -228,7 +228,7 @@ pub fn local_addr(&self) -> io::Result<SocketAddr> {
|
||||
/// let socket = UnixStream::connect("/tmp/sock").unwrap();
|
||||
/// let addr = socket.peer_addr().expect("Couldn't get peer address");
|
||||
/// ```
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
|
||||
Err(Error::new(ErrorKind::Other, "UnixStream::peer_addr unimplemented on redox"))
|
||||
}
|
||||
@@ -267,7 +267,7 @@ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
|
||||
/// let err = result.unwrap_err();
|
||||
/// assert_eq!(err.kind(), io::ErrorKind::InvalidInput)
|
||||
/// ```
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
pub fn set_read_timeout(&self, _timeout: Option<Duration>) -> io::Result<()> {
|
||||
Err(Error::new(ErrorKind::Other, "UnixStream::set_read_timeout unimplemented on redox"))
|
||||
}
|
||||
@@ -306,7 +306,7 @@ pub fn set_read_timeout(&self, _timeout: Option<Duration>) -> io::Result<()> {
|
||||
/// let err = result.unwrap_err();
|
||||
/// assert_eq!(err.kind(), io::ErrorKind::InvalidInput)
|
||||
/// ```
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
pub fn set_write_timeout(&self, _timeout: Option<Duration>) -> io::Result<()> {
|
||||
Err(Error::new(ErrorKind::Other, "UnixStream::set_write_timeout unimplemented on redox"))
|
||||
}
|
||||
@@ -323,7 +323,7 @@ pub fn set_write_timeout(&self, _timeout: Option<Duration>) -> io::Result<()> {
|
||||
/// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout");
|
||||
/// assert_eq!(socket.read_timeout().unwrap(), Some(Duration::new(1, 0)));
|
||||
/// ```
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
|
||||
Err(Error::new(ErrorKind::Other, "UnixStream::read_timeout unimplemented on redox"))
|
||||
}
|
||||
@@ -340,7 +340,7 @@ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
|
||||
/// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout");
|
||||
/// assert_eq!(socket.write_timeout().unwrap(), Some(Duration::new(1, 0)));
|
||||
/// ```
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
|
||||
Err(Error::new(ErrorKind::Other, "UnixStream::write_timeout unimplemented on redox"))
|
||||
}
|
||||
@@ -355,7 +355,7 @@ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
|
||||
/// let socket = UnixStream::connect("/tmp/sock").unwrap();
|
||||
/// socket.set_nonblocking(true).expect("Couldn't set nonblocking");
|
||||
/// ```
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
|
||||
self.0.set_nonblocking(nonblocking)
|
||||
}
|
||||
@@ -375,7 +375,7 @@ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
|
||||
///
|
||||
/// # Platform specific
|
||||
/// On Redox this always returns `None`.
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
|
||||
Ok(None)
|
||||
}
|
||||
@@ -397,13 +397,13 @@ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
|
||||
/// let socket = UnixStream::connect("/tmp/sock").unwrap();
|
||||
/// socket.shutdown(Shutdown::Both).expect("shutdown function failed");
|
||||
/// ```
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
pub fn shutdown(&self, _how: Shutdown) -> io::Result<()> {
|
||||
Err(Error::new(ErrorKind::Other, "UnixStream::shutdown unimplemented on redox"))
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
impl io::Read for UnixStream {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
io::Read::read(&mut &*self, buf)
|
||||
@@ -415,7 +415,7 @@ unsafe fn initializer(&self) -> Initializer {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
impl<'a> io::Read for &'a UnixStream {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.0.read(buf)
|
||||
@@ -427,7 +427,7 @@ unsafe fn initializer(&self) -> Initializer {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
impl io::Write for UnixStream {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
io::Write::write(&mut &*self, buf)
|
||||
@@ -438,7 +438,7 @@ fn flush(&mut self) -> io::Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
impl<'a> io::Write for &'a UnixStream {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.0.write(buf)
|
||||
@@ -449,21 +449,21 @@ fn flush(&mut self) -> io::Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
impl AsRawFd for UnixStream {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.raw()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
impl FromRawFd for UnixStream {
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> UnixStream {
|
||||
UnixStream(FileDesc::new(fd))
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
impl IntoRawFd for UnixStream {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.0.into_raw()
|
||||
@@ -498,10 +498,10 @@ fn into_raw_fd(self) -> RawFd {
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
pub struct UnixListener(FileDesc);
|
||||
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
impl fmt::Debug for UnixListener {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let mut builder = fmt.debug_struct("UnixListener");
|
||||
@@ -529,7 +529,7 @@ impl UnixListener {
|
||||
/// }
|
||||
/// };
|
||||
/// ```
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixListener> {
|
||||
if let Some(s) = path.as_ref().to_str() {
|
||||
cvt(syscall::open(format!("chan:{}", s), syscall::O_CREAT | syscall::O_CLOEXEC))
|
||||
@@ -563,7 +563,7 @@ pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixListener> {
|
||||
/// Err(e) => println!("accept function failed: {:?}", e),
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> {
|
||||
self.0.duplicate_path(b"listen").map(|fd| (UnixStream(fd), SocketAddr(())))
|
||||
}
|
||||
@@ -583,7 +583,7 @@ pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> {
|
||||
///
|
||||
/// let listener_copy = listener.try_clone().expect("try_clone failed");
|
||||
/// ```
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
pub fn try_clone(&self) -> io::Result<UnixListener> {
|
||||
self.0.duplicate().map(UnixListener)
|
||||
}
|
||||
@@ -599,7 +599,7 @@ pub fn try_clone(&self) -> io::Result<UnixListener> {
|
||||
///
|
||||
/// let addr = listener.local_addr().expect("Couldn't get local address");
|
||||
/// ```
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
pub fn local_addr(&self) -> io::Result<SocketAddr> {
|
||||
Err(Error::new(ErrorKind::Other, "UnixListener::local_addr unimplemented on redox"))
|
||||
}
|
||||
@@ -615,7 +615,7 @@ pub fn local_addr(&self) -> io::Result<SocketAddr> {
|
||||
///
|
||||
/// listener.set_nonblocking(true).expect("Couldn't set non blocking");
|
||||
/// ```
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
|
||||
self.0.set_nonblocking(nonblocking)
|
||||
}
|
||||
@@ -636,7 +636,7 @@ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
|
||||
///
|
||||
/// # Platform specific
|
||||
/// On Redox this always returns `None`.
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
|
||||
Ok(None)
|
||||
}
|
||||
@@ -672,34 +672,34 @@ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
pub fn incoming<'a>(&'a self) -> Incoming<'a> {
|
||||
Incoming { listener: self }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
impl AsRawFd for UnixListener {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.raw()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
impl FromRawFd for UnixListener {
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> UnixListener {
|
||||
UnixListener(FileDesc::new(fd))
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
impl IntoRawFd for UnixListener {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.0.into_raw()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
impl<'a> IntoIterator for &'a UnixListener {
|
||||
type Item = io::Result<UnixStream>;
|
||||
type IntoIter = Incoming<'a>;
|
||||
@@ -740,12 +740,12 @@ fn into_iter(self) -> Incoming<'a> {
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Debug)]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
pub struct Incoming<'a> {
|
||||
listener: &'a UnixListener,
|
||||
}
|
||||
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29")]
|
||||
#[stable(feature = "unix_socket_redox", since = "1.29.0")]
|
||||
impl<'a> Iterator for Incoming<'a> {
|
||||
type Item = io::Result<UnixStream>;
|
||||
|
||||
|
||||
@@ -109,15 +109,14 @@ pub fn walk_feature_fields<F>(&self, mut f: F)
|
||||
// stable (active).
|
||||
//
|
||||
// Note that the features should be grouped into internal/user-facing
|
||||
// and then sorted by version inside those groups.
|
||||
// FIXME(60361): Enforce ^-- with tidy.
|
||||
// and then sorted by version inside those groups. This is inforced with tidy.
|
||||
//
|
||||
// N.B., `tools/tidy/src/features.rs` parses this information directly out of the
|
||||
// source, so take care when modifying it.
|
||||
|
||||
declare_features! (
|
||||
// -------------------------------------------------------------------------
|
||||
// Internal feature gates.
|
||||
// feature-group-start: internal feature gates
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// no tracking issue START
|
||||
@@ -211,12 +210,12 @@ pub fn walk_feature_fields<F>(&self, mut f: F)
|
||||
|
||||
// no tracking issue END
|
||||
|
||||
// Allows using the `may_dangle` attribute (RFC 1327).
|
||||
(active, dropck_eyepatch, "1.10.0", Some(34761), None),
|
||||
|
||||
// Allows using `#[structural_match]` which indicates that a type is structurally matchable.
|
||||
(active, structural_match, "1.8.0", Some(31434), None),
|
||||
|
||||
// Allows using the `may_dangle` attribute (RFC 1327).
|
||||
(active, dropck_eyepatch, "1.10.0", Some(34761), None),
|
||||
|
||||
// Allows using the `#![panic_runtime]` attribute.
|
||||
(active, panic_runtime, "1.10.0", Some(32837), None),
|
||||
|
||||
@@ -252,7 +251,11 @@ pub fn walk_feature_fields<F>(&self, mut f: F)
|
||||
(active, test_2018_feature, "1.31.0", Some(0), Some(Edition::Edition2018)),
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Actual feature gates (target features).
|
||||
// feature-group-end: internal feature gates
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// feature-group-start: actual feature gates (target features)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// FIXME: Document these and merge with the list below.
|
||||
@@ -275,7 +278,11 @@ pub fn walk_feature_fields<F>(&self, mut f: F)
|
||||
(active, f16c_target_feature, "1.36.0", Some(44839), None),
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Actual feature gates.
|
||||
// feature-group-end: actual feature gates (target features)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// feature-group-start: actual feature gates
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// Allows using `asm!` macro with which inline assembly can be embedded.
|
||||
@@ -340,9 +347,6 @@ pub fn walk_feature_fields<F>(&self, mut f: F)
|
||||
// Permits specifying whether a function should permit unwinding or abort on unwind.
|
||||
(active, unwind_attributes, "1.4.0", Some(58760), None),
|
||||
|
||||
// Allows using `#[naked]` on functions.
|
||||
(active, naked_functions, "1.9.0", Some(32408), None),
|
||||
|
||||
// Allows `#[no_debug]`.
|
||||
(active, no_debug, "1.5.0", Some(29721), None),
|
||||
|
||||
@@ -358,6 +362,9 @@ pub fn walk_feature_fields<F>(&self, mut f: F)
|
||||
// Allows specialization of implementations (RFC 1210).
|
||||
(active, specialization, "1.7.0", Some(31844), None),
|
||||
|
||||
// Allows using `#[naked]` on functions.
|
||||
(active, naked_functions, "1.9.0", Some(32408), None),
|
||||
|
||||
// Allows `cfg(target_has_atomic = "...")`.
|
||||
(active, cfg_target_has_atomic, "1.9.0", Some(32976), None),
|
||||
|
||||
@@ -545,6 +552,10 @@ pub fn walk_feature_fields<F>(&self, mut f: F)
|
||||
|
||||
// Allows using C-variadics.
|
||||
(active, c_variadic, "1.34.0", Some(44930), None),
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// feature-group-end: actual feature gates
|
||||
// -------------------------------------------------------------------------
|
||||
);
|
||||
|
||||
// Some features are known to be incomplete and using them is likely to have
|
||||
|
||||
@@ -4,6 +4,7 @@ version = "0.1.0"
|
||||
authors = ["Alex Crichton <alex@alexcrichton.com>"]
|
||||
|
||||
[dependencies]
|
||||
regex = "1"
|
||||
serde = "1.0.8"
|
||||
serde_derive = "1.0.8"
|
||||
serde_json = "1.0.2"
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
//! * Library features have at most one stability level.
|
||||
//! * Library features have at most one `since` value.
|
||||
//! * All unstable lang features have tests to ensure they are actually unstable.
|
||||
//! * Language features in a group are sorted by `since` value.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
@@ -14,6 +15,14 @@
|
||||
use std::io::prelude::*;
|
||||
use std::path::Path;
|
||||
|
||||
use regex::{Regex, escape};
|
||||
|
||||
mod version;
|
||||
use self::version::Version;
|
||||
|
||||
const FEATURE_GROUP_START_PREFIX: &str = "// feature-group-start";
|
||||
const FEATURE_GROUP_END_PREFIX: &str = "// feature-group-end";
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum Status {
|
||||
Stable,
|
||||
@@ -35,7 +44,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Feature {
|
||||
pub level: Status,
|
||||
pub since: String,
|
||||
pub since: Option<Version>,
|
||||
pub has_gate_test: bool,
|
||||
pub tracking_issue: Option<u32>,
|
||||
}
|
||||
@@ -129,20 +138,8 @@ pub fn check(path: &Path, bad: &mut bool, quiet: bool) {
|
||||
}
|
||||
|
||||
let mut lines = Vec::new();
|
||||
for (name, feature) in features.iter() {
|
||||
lines.push(format!("{:<32} {:<8} {:<12} {:<8}",
|
||||
name,
|
||||
"lang",
|
||||
feature.level,
|
||||
feature.since));
|
||||
}
|
||||
for (name, feature) in lib_features {
|
||||
lines.push(format!("{:<32} {:<8} {:<12} {:<8}",
|
||||
name,
|
||||
"lib",
|
||||
feature.level,
|
||||
feature.since));
|
||||
}
|
||||
lines.extend(format_features(&features, "lang"));
|
||||
lines.extend(format_features(&lib_features, "lib"));
|
||||
|
||||
lines.sort();
|
||||
for line in lines {
|
||||
@@ -150,11 +147,31 @@ pub fn check(path: &Path, bad: &mut bool, quiet: bool) {
|
||||
}
|
||||
}
|
||||
|
||||
fn format_features<'a>(features: &'a Features, family: &'a str) -> impl Iterator<Item = String> + 'a {
|
||||
features.iter().map(move |(name, feature)| {
|
||||
format!("{:<32} {:<8} {:<12} {:<8}",
|
||||
name,
|
||||
family,
|
||||
feature.level,
|
||||
feature.since.map_or("None".to_owned(),
|
||||
|since| since.to_string()))
|
||||
})
|
||||
}
|
||||
|
||||
fn find_attr_val<'a>(line: &'a str, attr: &str) -> Option<&'a str> {
|
||||
line.find(attr)
|
||||
.and_then(|i| line[i..].find('"').map(|j| i + j + 1))
|
||||
.and_then(|i| line[i..].find('"').map(|j| (i, i + j)))
|
||||
.map(|(i, j)| &line[i..j])
|
||||
let r = Regex::new(&format!(r#"{}\s*=\s*"([^"]*)""#, escape(attr)))
|
||||
.expect("malformed regex for find_attr_val");
|
||||
r.captures(line)
|
||||
.and_then(|c| c.get(1))
|
||||
.map(|m| m.as_str())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_find_attr_val() {
|
||||
let s = r#"#[unstable(feature = "checked_duration_since", issue = "58402")]"#;
|
||||
assert_eq!(find_attr_val(s, "feature"), Some("checked_duration_since"));
|
||||
assert_eq!(find_attr_val(s, "issue"), Some("58402"));
|
||||
assert_eq!(find_attr_val(s, "since"), None);
|
||||
}
|
||||
|
||||
fn test_filen_gate(filen_underscore: &str, features: &mut Features) -> bool {
|
||||
@@ -177,6 +194,9 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features {
|
||||
// without one inside `// no tracking issue START` and `// no tracking issue END`.
|
||||
let mut next_feature_omits_tracking_issue = false;
|
||||
|
||||
let mut in_feature_group = false;
|
||||
let mut prev_since = None;
|
||||
|
||||
contents.lines().zip(1..)
|
||||
.filter_map(|(line, line_number)| {
|
||||
let line = line.trim();
|
||||
@@ -194,6 +214,25 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features {
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if line.starts_with(FEATURE_GROUP_START_PREFIX) {
|
||||
if in_feature_group {
|
||||
tidy_error!(
|
||||
bad,
|
||||
// ignore-tidy-linelength
|
||||
"libsyntax/feature_gate.rs:{}: new feature group is started without ending the previous one",
|
||||
line_number,
|
||||
);
|
||||
}
|
||||
|
||||
in_feature_group = true;
|
||||
prev_since = None;
|
||||
return None;
|
||||
} else if line.starts_with(FEATURE_GROUP_END_PREFIX) {
|
||||
in_feature_group = false;
|
||||
prev_since = None;
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut parts = line.split(',');
|
||||
let level = match parts.next().map(|l| l.trim().trim_start_matches('(')) {
|
||||
Some("active") => Status::Unstable,
|
||||
@@ -202,7 +241,33 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features {
|
||||
_ => return None,
|
||||
};
|
||||
let name = parts.next().unwrap().trim();
|
||||
let since = parts.next().unwrap().trim().trim_matches('"');
|
||||
|
||||
let since_str = parts.next().unwrap().trim().trim_matches('"');
|
||||
let since = match since_str.parse() {
|
||||
Ok(since) => Some(since),
|
||||
Err(err) => {
|
||||
tidy_error!(
|
||||
bad,
|
||||
"libsyntax/feature_gate.rs:{}: failed to parse since: {} ({:?})",
|
||||
line_number,
|
||||
since_str,
|
||||
err,
|
||||
);
|
||||
None
|
||||
}
|
||||
};
|
||||
if in_feature_group {
|
||||
if prev_since > since {
|
||||
tidy_error!(
|
||||
bad,
|
||||
"libsyntax/feature_gate.rs:{}: feature {} is not sorted by since",
|
||||
line_number,
|
||||
name,
|
||||
);
|
||||
}
|
||||
prev_since = since;
|
||||
}
|
||||
|
||||
let issue_str = parts.next().unwrap().trim();
|
||||
let tracking_issue = if issue_str.starts_with("None") {
|
||||
if level == Status::Unstable && !next_feature_omits_tracking_issue {
|
||||
@@ -222,7 +287,7 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features {
|
||||
Some((name.to_owned(),
|
||||
Feature {
|
||||
level,
|
||||
since: since.to_owned(),
|
||||
since,
|
||||
has_gate_test: false,
|
||||
tracking_issue,
|
||||
}))
|
||||
@@ -239,7 +304,7 @@ pub fn collect_lib_features(base_src_path: &Path) -> Features {
|
||||
// add it to the set of known library features so we can still generate docs.
|
||||
lib_features.insert("compiler_builtins_lib".to_owned(), Feature {
|
||||
level: Status::Unstable,
|
||||
since: String::new(),
|
||||
since: None,
|
||||
has_gate_test: false,
|
||||
tracking_issue: None,
|
||||
});
|
||||
@@ -336,11 +401,11 @@ macro_rules! err {
|
||||
// `const fn` features are handled specially.
|
||||
let feature_name = match find_attr_val(line, "feature") {
|
||||
Some(name) => name,
|
||||
None => err!("malformed stability attribute"),
|
||||
None => err!("malformed stability attribute: missing `feature` key"),
|
||||
};
|
||||
let feature = Feature {
|
||||
level: Status::Unstable,
|
||||
since: "None".to_owned(),
|
||||
since: None,
|
||||
has_gate_test: false,
|
||||
// FIXME(#57563): #57563 is now used as a common tracking issue,
|
||||
// although we would like to have specific tracking issues for each
|
||||
@@ -359,20 +424,23 @@ macro_rules! err {
|
||||
};
|
||||
let feature_name = match find_attr_val(line, "feature") {
|
||||
Some(name) => name,
|
||||
None => err!("malformed stability attribute"),
|
||||
None => err!("malformed stability attribute: missing `feature` key"),
|
||||
};
|
||||
let since = match find_attr_val(line, "since") {
|
||||
Some(name) => name,
|
||||
let since = match find_attr_val(line, "since").map(|x| x.parse()) {
|
||||
Some(Ok(since)) => Some(since),
|
||||
Some(Err(_err)) => {
|
||||
err!("malformed stability attribute: can't parse `since` key");
|
||||
},
|
||||
None if level == Status::Stable => {
|
||||
err!("malformed stability attribute");
|
||||
err!("malformed stability attribute: missing the `since` key");
|
||||
}
|
||||
None => "None",
|
||||
None => None,
|
||||
};
|
||||
let tracking_issue = find_attr_val(line, "issue").map(|s| s.parse().unwrap());
|
||||
|
||||
let feature = Feature {
|
||||
level,
|
||||
since: since.to_owned(),
|
||||
since,
|
||||
has_gate_test: false,
|
||||
tracking_issue,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
use std::str::FromStr;
|
||||
use std::num::ParseIntError;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Version {
|
||||
parts: [u32; 3],
|
||||
}
|
||||
|
||||
impl fmt::Display for Version {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.pad(&format!("{}.{}.{}", self.parts[0], self.parts[1], self.parts[2]))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum ParseVersionError {
|
||||
ParseIntError(ParseIntError),
|
||||
WrongNumberOfParts,
|
||||
}
|
||||
|
||||
impl From<ParseIntError> for ParseVersionError {
|
||||
fn from(err: ParseIntError) -> Self {
|
||||
ParseVersionError::ParseIntError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Version {
|
||||
type Err = ParseVersionError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let mut iter = s.split('.').map(|part| Ok(part.parse()?));
|
||||
|
||||
let parts = {
|
||||
let mut part = || {
|
||||
iter.next()
|
||||
.unwrap_or(Err(ParseVersionError::WrongNumberOfParts))
|
||||
};
|
||||
|
||||
[part()?, part()?, part()?]
|
||||
};
|
||||
|
||||
if let Some(_) = iter.next() {
|
||||
// Ensure we don't have more than 3 parts.
|
||||
return Err(ParseVersionError::WrongNumberOfParts);
|
||||
}
|
||||
|
||||
Ok(Self { parts })
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::Version;
|
||||
|
||||
#[test]
|
||||
fn test_try_from_invalid_version() {
|
||||
assert!("".parse::<Version>().is_err());
|
||||
assert!("hello".parse::<Version>().is_err());
|
||||
assert!("1.32.hi".parse::<Version>().is_err());
|
||||
assert!("1.32..1".parse::<Version>().is_err());
|
||||
assert!("1.32".parse::<Version>().is_err());
|
||||
assert!("1.32.0.1".parse::<Version>().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_try_from_single() {
|
||||
assert_eq!("1.32.0".parse(), Ok(Version { parts: [1, 32, 0] }));
|
||||
assert_eq!("1.0.0".parse(), Ok(Version { parts: [1, 0, 0] }));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compare() {
|
||||
let v_1_0_0 = "1.0.0".parse::<Version>().unwrap();
|
||||
let v_1_32_0 = "1.32.0".parse::<Version>().unwrap();
|
||||
let v_1_32_1 = "1.32.1".parse::<Version>().unwrap();
|
||||
assert!(v_1_0_0 < v_1_32_1);
|
||||
assert!(v_1_0_0 < v_1_32_0);
|
||||
assert!(v_1_32_0 < v_1_32_1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_string() {
|
||||
let v_1_0_0 = "1.0.0".parse::<Version>().unwrap();
|
||||
let v_1_32_1 = "1.32.1".parse::<Version>().unwrap();
|
||||
|
||||
assert_eq!(v_1_0_0.to_string(), "1.0.0");
|
||||
assert_eq!(v_1_32_1.to_string(), "1.32.1");
|
||||
assert_eq!(format!("{:<8}", v_1_32_1), "1.32.1 ");
|
||||
assert_eq!(format!("{:>8}", v_1_32_1), " 1.32.1");
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#![deny(rust_2018_idioms)]
|
||||
|
||||
extern crate regex;
|
||||
extern crate serde_json;
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
Reference in New Issue
Block a user