diff options
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/Cargo.toml | 2 | ||||
| -rw-r--r-- | src/libstd/collections/hash/map.rs | 49 | ||||
| -rw-r--r-- | src/libstd/error.rs | 10 | ||||
| -rw-r--r-- | src/libstd/ffi/c_str.rs | 2 | ||||
| -rw-r--r-- | src/libstd/fs.rs | 26 | ||||
| -rw-r--r-- | src/libstd/lib.rs | 1 | ||||
| -rw-r--r-- | src/libstd/net/udp.rs | 4 | ||||
| -rw-r--r-- | src/libstd/panic.rs | 32 | ||||
| -rw-r--r-- | src/libstd/panicking.rs | 34 | ||||
| -rw-r--r-- | src/libstd/path.rs | 9 | ||||
| -rw-r--r-- | src/libstd/rt.rs | 3 | ||||
| -rw-r--r-- | src/libstd/sync/mpsc/mod.rs | 20 | ||||
| -rw-r--r-- | src/libstd/sync/once.rs | 5 | ||||
| -rw-r--r-- | src/libstd/sys/unix/fs.rs | 227 | ||||
| -rw-r--r-- | src/libstd/sys/vxworks/fs.rs | 26 | ||||
| -rw-r--r-- | src/libstd/sys/vxworks/rwlock.rs | 2 | ||||
| -rw-r--r-- | src/libstd/sys/windows/fs.rs | 2 | ||||
| -rw-r--r-- | src/libstd/sys_common/backtrace.rs | 60 | ||||
| -rw-r--r-- | src/libstd/sys_common/os_str_bytes.rs | 8 | ||||
| -rw-r--r-- | src/libstd/thread/mod.rs | 3 | ||||
| -rw-r--r-- | src/libstd/time.rs | 51 |
21 files changed, 418 insertions, 158 deletions
diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index 0de9e6fcca5..1c99b091329 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -23,7 +23,7 @@ libc = { version = "0.2.51", default-features = false, features = ['rustc-dep-of compiler_builtins = { version = "0.1.16" } profiler_builtins = { path = "../libprofiler_builtins", optional = true } unwind = { path = "../libunwind" } -hashbrown = { version = "0.5.0", features = ['rustc-dep-of-std'] } +hashbrown = { version = "0.6.1", default-features = false, features = ['rustc-dep-of-std'] } [dependencies.backtrace_rs] package = "backtrace" diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index ff50051ef50..6b0225a1b44 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -2030,6 +2030,31 @@ impl<'a, K, V> Entry<'a, K, V> { Vacant(entry) => Vacant(entry), } } + + /// Sets the value of the entry, and returns an OccupiedEntry. + /// + /// # Examples + /// + /// ``` + /// #![feature(entry_insert)] + /// use std::collections::HashMap; + /// + /// let mut map: HashMap<&str, String> = HashMap::new(); + /// let entry = map.entry("poneyland").insert("hoho".to_string()); + /// + /// assert_eq!(entry.key(), &"poneyland"); + /// ``` + #[inline] + #[unstable(feature = "entry_insert", issue = "65225")] + pub fn insert(self, value: V) -> OccupiedEntry<'a, K, V> { + match self { + Occupied(mut entry) => { + entry.insert(value); + entry + }, + Vacant(entry) => entry.insert_entry(value), + } + } } impl<'a, K, V: Default> Entry<'a, K, V> { @@ -2347,6 +2372,28 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { pub fn insert(self, value: V) -> &'a mut V { self.base.insert(value) } + + /// Sets the value of the entry with the VacantEntry's key, + /// and returns an OccupiedEntry. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// use std::collections::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let Entry::Vacant(o) = map.entry("poneyland") { + /// o.insert(37); + /// } + /// assert_eq!(map["poneyland"], 37); + /// ``` + #[inline] + fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V> { + let base = self.base.insert_entry(value); + OccupiedEntry { base } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -2362,6 +2409,8 @@ where } } +/// Inserts all new key-values from the iterator and replaces values with existing +/// keys with new values returned from the iterator. #[stable(feature = "rust1", since = "1.0.0")] impl<K, V, S> Extend<(K, V)> for HashMap<K, V, S> where diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 4a1bb75d588..6b9a35fccc4 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -269,8 +269,8 @@ impl<'a, E: Error + 'a> From<E> for Box<dyn Error + 'a> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<dyn Error + Send + Sync + 'a> { - /// Converts a type of [`Error`] + [`trait@Send`] + [`trait@Sync`] into a box of - /// dyn [`Error`] + [`trait@Send`] + [`trait@Sync`]. + /// Converts a type of [`Error`] + [`Send`] + [`Sync`] into a box of + /// dyn [`Error`] + [`Send`] + [`Sync`]. /// /// [`Error`]: ../error/trait.Error.html /// @@ -313,7 +313,7 @@ impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<dyn Error + Send + Sync + #[stable(feature = "rust1", since = "1.0.0")] impl From<String> for Box<dyn Error + Send + Sync> { - /// Converts a [`String`] into a box of dyn [`Error`] + [`trait@Send`] + [`trait@Sync`]. + /// Converts a [`String`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. /// /// [`Error`]: ../error/trait.Error.html /// @@ -377,7 +377,7 @@ impl From<String> for Box<dyn Error> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a> From<&str> for Box<dyn Error + Send + Sync + 'a> { - /// Converts a [`str`] into a box of dyn [`Error`] + [`trait@Send`] + [`trait@Sync`]. + /// Converts a [`str`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. /// /// [`Error`]: ../error/trait.Error.html /// @@ -420,7 +420,7 @@ impl From<&str> for Box<dyn Error> { #[stable(feature = "cow_box_error", since = "1.22.0")] impl<'a, 'b> From<Cow<'b, str>> for Box<dyn Error + Send + Sync + 'a> { - /// Converts a [`Cow`] into a box of dyn [`Error`] + [`trait@Send`] + [`trait@Sync`]. + /// Converts a [`Cow`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. /// /// [`Cow`]: ../borrow/enum.Cow.html /// [`Error`]: ../error/trait.Error.html diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index d7f4cc5d1fd..483f2ba52ec 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -919,7 +919,7 @@ impl Error for IntoStringError { "C string contained non-utf8 bytes" } - fn cause(&self) -> Option<&dyn Error> { + fn source(&self) -> Option<&(dyn Error + 'static)> { Some(&self.error) } } diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 8933f027a06..6595f54162f 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -1090,13 +1090,14 @@ impl Metadata { /// Returns the creation time listed in this metadata. /// - /// The returned value corresponds to the `birthtime` field of `stat` on - /// Unix platforms and the `ftCreationTime` field on Windows platforms. + /// The returned value corresponds to the `btime` field of `statx` on + /// Linux kernel starting from to 4.11, the `birthtime` field of `stat` on other + /// Unix platforms, and the `ftCreationTime` field on Windows platforms. /// /// # Errors /// /// This field may not be available on all platforms, and will return an - /// `Err` on platforms where it is not available. + /// `Err` on platforms or filesystems where it is not available. /// /// # Examples /// @@ -1109,7 +1110,7 @@ impl Metadata { /// if let Ok(time) = metadata.created() { /// println!("{:?}", time); /// } else { - /// println!("Not supported on this platform"); + /// println!("Not supported on this platform or filesystem"); /// } /// Ok(()) /// } @@ -3112,8 +3113,10 @@ mod tests { #[cfg(windows)] let invalid_options = 87; // ERROR_INVALID_PARAMETER - #[cfg(unix)] + #[cfg(all(unix, not(target_os = "vxworks")))] let invalid_options = "Invalid argument"; + #[cfg(target_os = "vxworks")] + let invalid_options = "invalid argument"; // Test various combinations of creation modes and access modes. // @@ -3441,5 +3444,18 @@ mod tests { check!(a.created()); check!(b.created()); } + + if cfg!(target_os = "linux") { + // Not always available + match (a.created(), b.created()) { + (Ok(t1), Ok(t2)) => assert!(t1 <= t2), + (Err(e1), Err(e2)) if e1.kind() == ErrorKind::Other && + e2.kind() == ErrorKind::Other => {} + (a, b) => panic!( + "creation time must be always supported or not supported: {:?} {:?}", + a, b, + ), + } + } } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 5ff32d7adaf..af6cb656444 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -277,7 +277,6 @@ #![feature(log_syntax)] #![feature(maybe_uninit_ref)] #![feature(maybe_uninit_slice)] -#![feature(mem_take)] #![feature(needs_panic_runtime)] #![feature(never_type)] #![feature(nll)] diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index a5e7cd992f2..46bbd8855de 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -185,7 +185,6 @@ impl UdpSocket { /// # Examples /// /// ```no_run - /// #![feature(udp_peer_addr)] /// use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, UdpSocket}; /// /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); @@ -199,14 +198,13 @@ impl UdpSocket { /// [`NotConnected`]: ../../std/io/enum.ErrorKind.html#variant.NotConnected /// /// ```no_run - /// #![feature(udp_peer_addr)] /// use std::net::UdpSocket; /// /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); /// assert_eq!(socket.peer_addr().unwrap_err().kind(), /// ::std::io::ErrorKind::NotConnected); /// ``` - #[unstable(feature = "udp_peer_addr", issue = "59127")] + #[stable(feature = "udp_peer_addr", since = "1.40.0")] pub fn peer_addr(&self) -> io::Result<SocketAddr> { self.0.peer_addr() } diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 1d4fd98dd75..24c693790e8 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -12,7 +12,9 @@ use crate::ops::{Deref, DerefMut}; use crate::panicking; use crate::ptr::{Unique, NonNull}; use crate::rc::Rc; -use crate::sync::{Arc, Mutex, RwLock, atomic}; +use crate::sync::{Arc, Mutex, RwLock}; +#[cfg(not(bootstrap))] +use crate::sync::atomic; use crate::task::{Context, Poll}; use crate::thread::Result; @@ -240,49 +242,49 @@ impl<T: ?Sized> RefUnwindSafe for Mutex<T> {} #[stable(feature = "unwind_safe_lock_refs", since = "1.12.0")] impl<T: ?Sized> RefUnwindSafe for RwLock<T> {} -#[cfg(target_has_atomic = "ptr")] +#[cfg(target_has_atomic_load_store = "ptr")] #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] impl RefUnwindSafe for atomic::AtomicIsize {} -#[cfg(target_has_atomic = "8")] +#[cfg(target_has_atomic_load_store = "8")] #[unstable(feature = "integer_atomics", issue = "32976")] impl RefUnwindSafe for atomic::AtomicI8 {} -#[cfg(target_has_atomic = "16")] +#[cfg(target_has_atomic_load_store = "16")] #[unstable(feature = "integer_atomics", issue = "32976")] impl RefUnwindSafe for atomic::AtomicI16 {} -#[cfg(target_has_atomic = "32")] +#[cfg(target_has_atomic_load_store = "32")] #[unstable(feature = "integer_atomics", issue = "32976")] impl RefUnwindSafe for atomic::AtomicI32 {} -#[cfg(target_has_atomic = "64")] +#[cfg(target_has_atomic_load_store = "64")] #[unstable(feature = "integer_atomics", issue = "32976")] impl RefUnwindSafe for atomic::AtomicI64 {} -#[cfg(target_has_atomic = "128")] +#[cfg(target_has_atomic_load_store = "128")] #[unstable(feature = "integer_atomics", issue = "32976")] impl RefUnwindSafe for atomic::AtomicI128 {} -#[cfg(target_has_atomic = "ptr")] +#[cfg(target_has_atomic_load_store = "ptr")] #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] impl RefUnwindSafe for atomic::AtomicUsize {} -#[cfg(target_has_atomic = "8")] +#[cfg(target_hastarget_has_atomic_load_store_atomic = "8")] #[unstable(feature = "integer_atomics", issue = "32976")] impl RefUnwindSafe for atomic::AtomicU8 {} -#[cfg(target_has_atomic = "16")] +#[cfg(target_has_atomic_load_store = "16")] #[unstable(feature = "integer_atomics", issue = "32976")] impl RefUnwindSafe for atomic::AtomicU16 {} -#[cfg(target_has_atomic = "32")] +#[cfg(target_has_atomic_load_store = "32")] #[unstable(feature = "integer_atomics", issue = "32976")] impl RefUnwindSafe for atomic::AtomicU32 {} -#[cfg(target_has_atomic = "64")] +#[cfg(target_has_atomic_load_store = "64")] #[unstable(feature = "integer_atomics", issue = "32976")] impl RefUnwindSafe for atomic::AtomicU64 {} -#[cfg(target_has_atomic = "128")] +#[cfg(target_has_atomic_load_store = "128")] #[unstable(feature = "integer_atomics", issue = "32976")] impl RefUnwindSafe for atomic::AtomicU128 {} -#[cfg(target_has_atomic = "8")] +#[cfg(target_has_atomic_load_store = "8")] #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] impl RefUnwindSafe for atomic::AtomicBool {} -#[cfg(target_has_atomic = "ptr")] +#[cfg(target_has_atomic_load_store = "ptr")] #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] impl<T> RefUnwindSafe for atomic::AtomicPtr<T> {} diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 28fb4024404..638ce1679b8 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -15,9 +15,11 @@ use crate::intrinsics; use crate::mem; use crate::ptr; use crate::raw; +use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sys::stdio::panic_output; use crate::sys_common::rwlock::RWLock; -use crate::sys_common::{thread_info, util, backtrace}; +use crate::sys_common::{thread_info, util}; +use crate::sys_common::backtrace::{self, RustBacktrace}; use crate::thread; #[cfg(not(test))] @@ -158,16 +160,10 @@ pub fn take_hook() -> Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send> { fn default_hook(info: &PanicInfo<'_>) { // If this is a double panic, make sure that we print a backtrace // for this panic. Otherwise only print it if logging is enabled. - let log_backtrace = if cfg!(feature = "backtrace") { - let panics = update_panic_count(0); - - if panics >= 2 { - Some(backtrace_rs::PrintFmt::Full) - } else { - backtrace::log_enabled() - } + let backtrace_env = if update_panic_count(0) >= 2 { + RustBacktrace::Print(backtrace_rs::PrintFmt::Full) } else { - None + backtrace::rust_backtrace_env() }; // The current implementation always returns `Some`. @@ -187,16 +183,16 @@ fn default_hook(info: &PanicInfo<'_>) { let _ = writeln!(err, "thread '{}' panicked at '{}', {}", name, msg, location); - if cfg!(feature = "backtrace") { - use crate::sync::atomic::{AtomicBool, Ordering}; - - static FIRST_PANIC: AtomicBool = AtomicBool::new(true); + static FIRST_PANIC: AtomicBool = AtomicBool::new(true); - if let Some(format) = log_backtrace { - let _ = backtrace::print(err, format); - } else if FIRST_PANIC.compare_and_swap(true, false, Ordering::SeqCst) { - let _ = writeln!(err, "note: run with `RUST_BACKTRACE=1` \ - environment variable to display a backtrace."); + match backtrace_env { + RustBacktrace::Print(format) => drop(backtrace::print(err, format)), + RustBacktrace::Disabled => {} + RustBacktrace::RuntimeDisabled => { + if FIRST_PANIC.swap(false, Ordering::SeqCst) { + let _ = writeln!(err, "note: run with `RUST_BACKTRACE=1` \ + environment variable to display a backtrace."); + } } } }; diff --git a/src/libstd/path.rs b/src/libstd/path.rs index fd6ff1032bb..ca81044ee85 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1627,7 +1627,7 @@ impl<'a> From<Cow<'a, Path>> for PathBuf { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<PathBuf> for Arc<Path> { - /// Converts a Path into a Rc by copying the Path data into a new Rc buffer. + /// Converts a `PathBuf` into an `Arc` by moving the `PathBuf` data into a new `Arc` buffer. #[inline] fn from(s: PathBuf) -> Arc<Path> { let arc: Arc<OsStr> = Arc::from(s.into_os_string()); @@ -1637,7 +1637,7 @@ impl From<PathBuf> for Arc<Path> { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<&Path> for Arc<Path> { - /// Converts a Path into a Rc by copying the Path data into a new Rc buffer. + /// Converts a `Path` into an `Arc` by copying the `Path` data into a new `Arc` buffer. #[inline] fn from(s: &Path) -> Arc<Path> { let arc: Arc<OsStr> = Arc::from(s.as_os_str()); @@ -1647,7 +1647,7 @@ impl From<&Path> for Arc<Path> { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<PathBuf> for Rc<Path> { - /// Converts a Path into a Rc by copying the Path data into a new Rc buffer. + /// Converts a `PathBuf` into an `Rc` by moving the `PathBuf` data into a new `Rc` buffer. #[inline] fn from(s: PathBuf) -> Rc<Path> { let rc: Rc<OsStr> = Rc::from(s.into_os_string()); @@ -1657,7 +1657,7 @@ impl From<PathBuf> for Rc<Path> { #[stable(feature = "shared_from_slice2", since = "1.24.0")] impl From<&Path> for Rc<Path> { - /// Converts a Path into a Rc by copying the Path data into a new Rc buffer. + /// Converts a `Path` into an `Rc` by copying the `Path` data into a new `Rc` buffer. #[inline] fn from(s: &Path) -> Rc<Path> { let rc: Rc<OsStr> = Rc::from(s.as_os_str()); @@ -2219,6 +2219,7 @@ impl Path { /// assert_eq!(Path::new("/etc").join("passwd"), PathBuf::from("/etc/passwd")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] pub fn join<P: AsRef<Path>>(&self, path: P) -> PathBuf { self._join(path.as_ref()) } diff --git a/src/libstd/rt.rs b/src/libstd/rt.rs index cf45eb0daba..63e35d5ed91 100644 --- a/src/libstd/rt.rs +++ b/src/libstd/rt.rs @@ -44,12 +44,9 @@ fn lang_start_internal(main: &(dyn Fn() -> i32 + Sync + crate::panic::RefUnwindS sys::args::init(argc, argv); // Let's run some code! - #[cfg(feature = "backtrace")] let exit_code = panic::catch_unwind(|| { sys_common::backtrace::__rust_begin_short_backtrace(move || main()) }); - #[cfg(not(feature = "backtrace"))] - let exit_code = panic::catch_unwind(move || main()); sys_common::cleanup(); exit_code.unwrap_or(101) as isize diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 69ecd201063..c2884a28f3c 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -1581,10 +1581,6 @@ impl<T: Send> error::Error for SendError<T> { fn description(&self) -> &str { "sending on a closed channel" } - - fn cause(&self) -> Option<&dyn error::Error> { - None - } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1624,10 +1620,6 @@ impl<T: Send> error::Error for TrySendError<T> { } } } - - fn cause(&self) -> Option<&dyn error::Error> { - None - } } #[stable(feature = "mpsc_error_conversions", since = "1.24.0")] @@ -1652,10 +1644,6 @@ impl error::Error for RecvError { fn description(&self) -> &str { "receiving on a closed channel" } - - fn cause(&self) -> Option<&dyn error::Error> { - None - } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1685,10 +1673,6 @@ impl error::Error for TryRecvError { } } } - - fn cause(&self) -> Option<&dyn error::Error> { - None - } } #[stable(feature = "mpsc_error_conversions", since = "1.24.0")] @@ -1726,10 +1710,6 @@ impl error::Error for RecvTimeoutError { } } } - - fn cause(&self) -> Option<&dyn error::Error> { - None - } } #[stable(feature = "mpsc_error_conversions", since = "1.24.0")] diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs index e529b8c4227..e28fbca7fa1 100644 --- a/src/libstd/sync/once.rs +++ b/src/libstd/sync/once.rs @@ -60,10 +60,9 @@ use crate::thread::{self, Thread}; /// A synchronization primitive which can be used to run a one-time global /// initialization. Useful for one-time initialization for FFI or related -/// functionality. This type can only be constructed with the [`ONCE_INIT`] -/// value or the equivalent [`Once::new`] constructor. +/// functionality. This type can only be constructed with the [`Once::new`] +/// constructor. /// -/// [`ONCE_INIT`]: constant.ONCE_INIT.html /// [`Once::new`]: struct.Once.html#method.new /// /// # Examples diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index c2064fca23e..4054cb1f9c5 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -41,11 +41,138 @@ pub use crate::sys_common::fs::remove_dir_all; pub struct File(FileDesc); -#[derive(Clone)] -pub struct FileAttr { - stat: stat64, +// FIXME: This should be available on Linux with all `target_arch` and `target_env`. +// https://github.com/rust-lang/libc/issues/1545 +macro_rules! cfg_has_statx { + ({ $($then_tt:tt)* } else { $($else_tt:tt)* }) => { + cfg_if::cfg_if! { + if #[cfg(all(target_os = "linux", target_env = "gnu", any( + target_arch = "x86", + target_arch = "arm", + // target_arch = "mips", + target_arch = "powerpc", + target_arch = "x86_64", + // target_arch = "aarch64", + target_arch = "powerpc64", + // target_arch = "mips64", + // target_arch = "s390x", + target_arch = "sparc64", + )))] { + $($then_tt)* + } else { + $($else_tt)* + } + } + }; + ($($block_inner:tt)*) => { + #[cfg(all(target_os = "linux", target_env = "gnu", any( + target_arch = "x86", + target_arch = "arm", + // target_arch = "mips", + target_arch = "powerpc", + target_arch = "x86_64", + // target_arch = "aarch64", + target_arch = "powerpc64", + // target_arch = "mips64", + // target_arch = "s390x", + target_arch = "sparc64", + )))] + { + $($block_inner)* + } + }; } +cfg_has_statx! {{ + #[derive(Clone)] + pub struct FileAttr { + stat: stat64, + statx_extra_fields: Option<StatxExtraFields>, + } + + #[derive(Clone)] + struct StatxExtraFields { + // This is needed to check if btime is supported by the filesystem. + stx_mask: u32, + stx_btime: libc::statx_timestamp, + } + + // We prefer `statx` on Linux if available, which contains file creation time. + // Default `stat64` contains no creation time. + unsafe fn try_statx( + fd: c_int, + path: *const libc::c_char, + flags: i32, + mask: u32, + ) -> Option<io::Result<FileAttr>> { + use crate::sync::atomic::{AtomicBool, Ordering}; + + // Linux kernel prior to 4.11 or glibc prior to glibc 2.28 don't support `statx` + // We store the availability in a global to avoid unnecessary syscalls + static HAS_STATX: AtomicBool = AtomicBool::new(true); + syscall! { + fn statx( + fd: c_int, + pathname: *const libc::c_char, + flags: c_int, + mask: libc::c_uint, + statxbuf: *mut libc::statx + ) -> c_int + } + + if !HAS_STATX.load(Ordering::Relaxed) { + return None; + } + + let mut buf: libc::statx = mem::zeroed(); + let ret = cvt(statx(fd, path, flags, mask, &mut buf)); + match ret { + Err(err) => match err.raw_os_error() { + Some(libc::ENOSYS) => { + HAS_STATX.store(false, Ordering::Relaxed); + return None; + } + _ => return Some(Err(err)), + } + Ok(_) => { + // We cannot fill `stat64` exhaustively because of private padding fields. + let mut stat: stat64 = mem::zeroed(); + // `c_ulong` on gnu-mips, `dev_t` otherwise + stat.st_dev = libc::makedev(buf.stx_dev_major, buf.stx_dev_minor) as _; + stat.st_ino = buf.stx_ino as libc::ino64_t; + stat.st_nlink = buf.stx_nlink as libc::nlink_t; + stat.st_mode = buf.stx_mode as libc::mode_t; + stat.st_uid = buf.stx_uid as libc::uid_t; + stat.st_gid = buf.stx_gid as libc::gid_t; + stat.st_rdev = libc::makedev(buf.stx_rdev_major, buf.stx_rdev_minor) as _; + stat.st_size = buf.stx_size as off64_t; + stat.st_blksize = buf.stx_blksize as libc::blksize_t; + stat.st_blocks = buf.stx_blocks as libc::blkcnt64_t; + stat.st_atime = buf.stx_atime.tv_sec as libc::time_t; + // `i64` on gnu-x86_64-x32, `c_ulong` otherwise. + stat.st_atime_nsec = buf.stx_atime.tv_nsec as _; + stat.st_mtime = buf.stx_mtime.tv_sec as libc::time_t; + stat.st_mtime_nsec = buf.stx_mtime.tv_nsec as _; + stat.st_ctime = buf.stx_ctime.tv_sec as libc::time_t; + stat.st_ctime_nsec = buf.stx_ctime.tv_nsec as _; + + let extra = StatxExtraFields { + stx_mask: buf.stx_mask, + stx_btime: buf.stx_btime, + }; + + Some(Ok(FileAttr { stat, statx_extra_fields: Some(extra) })) + } + } + } + +} else { + #[derive(Clone)] + pub struct FileAttr { + stat: stat64, + } +}} + // all DirEntry's will have a reference to this struct struct InnerReadDir { dirp: Dir, @@ -97,6 +224,20 @@ pub struct FileType { mode: mode_t } #[derive(Debug)] pub struct DirBuilder { mode: mode_t } +cfg_has_statx! {{ + impl FileAttr { + fn from_stat64(stat: stat64) -> Self { + Self { stat, statx_extra_fields: None } + } + } +} else { + impl FileAttr { + fn from_stat64(stat: stat64) -> Self { + Self { stat } + } + } +}} + impl FileAttr { pub fn size(&self) -> u64 { self.stat.st_size as u64 } pub fn perm(&self) -> FilePermissions { @@ -164,6 +305,22 @@ impl FileAttr { target_os = "macos", target_os = "ios")))] pub fn created(&self) -> io::Result<SystemTime> { + cfg_has_statx! { + if let Some(ext) = &self.statx_extra_fields { + return if (ext.stx_mask & libc::STATX_BTIME) != 0 { + Ok(SystemTime::from(libc::timespec { + tv_sec: ext.stx_btime.tv_sec as libc::time_t, + tv_nsec: ext.stx_btime.tv_nsec as _, + })) + } else { + Err(io::Error::new( + io::ErrorKind::Other, + "creation time is not available for the filesystem", + )) + }; + } + } + Err(io::Error::new(io::ErrorKind::Other, "creation time is not available on this platform \ currently")) @@ -306,12 +463,25 @@ impl DirEntry { #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))] pub fn metadata(&self) -> io::Result<FileAttr> { - let fd = cvt(unsafe {dirfd(self.dir.inner.dirp.0)})?; + let fd = cvt(unsafe { dirfd(self.dir.inner.dirp.0) })?; + let name = self.entry.d_name.as_ptr(); + + cfg_has_statx! { + if let Some(ret) = unsafe { try_statx( + fd, + name, + libc::AT_SYMLINK_NOFOLLOW | libc::AT_STATX_SYNC_AS_STAT, + libc::STATX_ALL, + ) } { + return ret; + } + } + let mut stat: stat64 = unsafe { mem::zeroed() }; cvt(unsafe { - fstatat64(fd, self.entry.d_name.as_ptr(), &mut stat, libc::AT_SYMLINK_NOFOLLOW) + fstatat64(fd, name, &mut stat, libc::AT_SYMLINK_NOFOLLOW) })?; - Ok(FileAttr { stat }) + Ok(FileAttr::from_stat64(stat)) } #[cfg(not(any(target_os = "linux", target_os = "emscripten", target_os = "android")))] @@ -515,11 +685,24 @@ impl File { } pub fn file_attr(&self) -> io::Result<FileAttr> { + let fd = self.0.raw(); + + cfg_has_statx! { + if let Some(ret) = unsafe { try_statx( + fd, + b"\0" as *const _ as *const libc::c_char, + libc::AT_EMPTY_PATH | libc::AT_STATX_SYNC_AS_STAT, + libc::STATX_ALL, + ) } { + return ret; + } + } + let mut stat: stat64 = unsafe { mem::zeroed() }; cvt(unsafe { - fstat64(self.0.raw(), &mut stat) + fstat64(fd, &mut stat) })?; - Ok(FileAttr { stat }) + Ok(FileAttr::from_stat64(stat)) } pub fn fsync(&self) -> io::Result<()> { @@ -796,20 +979,44 @@ pub fn link(src: &Path, dst: &Path) -> io::Result<()> { pub fn stat(p: &Path) -> io::Result<FileAttr> { let p = cstr(p)?; + + cfg_has_statx! { + if let Some(ret) = unsafe { try_statx( + libc::AT_FDCWD, + p.as_ptr(), + libc::AT_STATX_SYNC_AS_STAT, + libc::STATX_ALL, + ) } { + return ret; + } + } + let mut stat: stat64 = unsafe { mem::zeroed() }; cvt(unsafe { stat64(p.as_ptr(), &mut stat) })?; - Ok(FileAttr { stat }) + Ok(FileAttr::from_stat64(stat)) } pub fn lstat(p: &Path) -> io::Result<FileAttr> { let p = cstr(p)?; + + cfg_has_statx! { + if let Some(ret) = unsafe { try_statx( + libc::AT_FDCWD, + p.as_ptr(), + libc::AT_SYMLINK_NOFOLLOW | libc::AT_STATX_SYNC_AS_STAT, + libc::STATX_ALL, + ) } { + return ret; + } + } + let mut stat: stat64 = unsafe { mem::zeroed() }; cvt(unsafe { lstat64(p.as_ptr(), &mut stat) })?; - Ok(FileAttr { stat }) + Ok(FileAttr::from_stat64(stat)) } pub fn canonicalize(p: &Path) -> io::Result<PathBuf> { diff --git a/src/libstd/sys/vxworks/fs.rs b/src/libstd/sys/vxworks/fs.rs index 51fdb1c0e55..adb08d8005a 100644 --- a/src/libstd/sys/vxworks/fs.rs +++ b/src/libstd/sys/vxworks/fs.rs @@ -400,13 +400,27 @@ impl FromInner<c_int> for File { impl fmt::Debug for File { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fn get_path(_fd: c_int) -> Option<PathBuf> { - // FIXME(#:(): implement this for VxWorks - None + fn get_path(fd: c_int) -> Option<PathBuf> { + let mut buf = vec![0;libc::PATH_MAX as usize]; + let n = unsafe { libc::ioctl(fd, libc::FIOGETNAME, buf.as_ptr()) }; + if n == -1 { + return None; + } + let l = buf.iter().position(|&c| c == 0).unwrap(); + buf.truncate(l as usize); + Some(PathBuf::from(OsString::from_vec(buf))) } - fn get_mode(_fd: c_int) -> Option<(bool, bool)> { - // FIXME(#:(): implement this for VxWorks - None + fn get_mode(fd: c_int) -> Option<(bool, bool)> { + let mode = unsafe { libc::fcntl(fd, libc::F_GETFL) }; + if mode == -1 { + return None; + } + match mode & libc::O_ACCMODE { + libc::O_RDONLY => Some((true, false)), + libc::O_RDWR => Some((true, true)), + libc::O_WRONLY => Some((false, true)), + _ => None + } } let fd = self.0.raw(); diff --git a/src/libstd/sys/vxworks/rwlock.rs b/src/libstd/sys/vxworks/rwlock.rs index 718f422ed11..19b123f2b61 100644 --- a/src/libstd/sys/vxworks/rwlock.rs +++ b/src/libstd/sys/vxworks/rwlock.rs @@ -25,7 +25,7 @@ impl RWLock { let r = libc::pthread_rwlock_rdlock(self.inner.get()); if r == libc::EAGAIN { panic!("rwlock maximum reader count exceeded"); - } else if r == libc::EDEADLK || *self.write_locked.get() { + } else if r == libc::EDEADLK || (r == 0 && *self.write_locked.get()) { if r == 0 { self.raw_unlock(); } diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 204f6af5fc1..4160123c9a2 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -412,7 +412,7 @@ impl File { pub fn duplicate(&self) -> io::Result<File> { Ok(File { - handle: self.handle.duplicate(0, true, c::DUPLICATE_SAME_ACCESS)?, + handle: self.handle.duplicate(0, false, c::DUPLICATE_SAME_ACCESS)?, }) } diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs index 01711d415d8..9c406ec39cc 100644 --- a/src/libstd/sys_common/backtrace.rs +++ b/src/libstd/sys_common/backtrace.rs @@ -7,6 +7,7 @@ use crate::io; use crate::borrow::Cow; use crate::io::prelude::*; use crate::path::{self, Path, PathBuf}; +use crate::sync::atomic::{self, Ordering}; use crate::sys::mutex::Mutex; use backtrace_rs::{BacktraceFmt, BytesOrWideString, PrintFmt}; @@ -115,8 +116,10 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt:: Ok(()) } -/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. -#[inline(never)] +/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that +/// this is only inline(never) when backtraces in libstd are enabled, otherwise +/// it's fine to optimize away. +#[cfg_attr(feature = "backtrace", inline(never))] pub fn __rust_begin_short_backtrace<F, T>(f: F) -> T where F: FnOnce() -> T, @@ -126,42 +129,49 @@ where f() } +pub enum RustBacktrace { + Print(PrintFmt), + Disabled, + RuntimeDisabled, +} + // For now logging is turned off by default, and this function checks to see // whether the magical environment variable is present to see if it's turned on. -pub fn log_enabled() -> Option<PrintFmt> { - use crate::sync::atomic::{self, Ordering}; +pub fn rust_backtrace_env() -> RustBacktrace { + // If the `backtrace` feature of this crate isn't enabled quickly return + // `None` so this can be constant propagated all over the place to turn + // optimize away callers. + if !cfg!(feature = "backtrace") { + return RustBacktrace::Disabled; + } // Setting environment variables for Fuchsia components isn't a standard // or easily supported workflow. For now, always display backtraces. if cfg!(target_os = "fuchsia") { - return Some(PrintFmt::Full); + return RustBacktrace::Print(PrintFmt::Full); } static ENABLED: atomic::AtomicIsize = atomic::AtomicIsize::new(0); match ENABLED.load(Ordering::SeqCst) { 0 => {} - 1 => return None, - 2 => return Some(PrintFmt::Short), - _ => return Some(PrintFmt::Full), + 1 => return RustBacktrace::RuntimeDisabled, + 2 => return RustBacktrace::Print(PrintFmt::Short), + _ => return RustBacktrace::Print(PrintFmt::Full), } - let val = env::var_os("RUST_BACKTRACE").and_then(|x| { - if &x == "0" { - None - } else if &x == "full" { - Some(PrintFmt::Full) - } else { - Some(PrintFmt::Short) - } - }); - ENABLED.store( - match val { - Some(v) => v as isize, - None => 1, - }, - Ordering::SeqCst, - ); - val + let (format, cache) = env::var_os("RUST_BACKTRACE") + .map(|x| { + if &x == "0" { + (RustBacktrace::RuntimeDisabled, 1) + } else if &x == "full" { + (RustBacktrace::Print(PrintFmt::Full), 3) + } else { + (RustBacktrace::Print(PrintFmt::Short), 2) + } + }) + .unwrap_or((RustBacktrace::RuntimeDisabled, 1)); + ENABLED.store(cache, Ordering::SeqCst); + format } /// Prints the filename of the backtrace frame. diff --git a/src/libstd/sys_common/os_str_bytes.rs b/src/libstd/sys_common/os_str_bytes.rs index d734f412bf8..3753269adfe 100644 --- a/src/libstd/sys_common/os_str_bytes.rs +++ b/src/libstd/sys_common/os_str_bytes.rs @@ -193,7 +193,7 @@ impl Slice { pub trait OsStringExt { /// Creates an [`OsString`] from a byte vector. /// - /// See the module docmentation for an example. + /// See the module documentation for an example. /// /// [`OsString`]: ../../../ffi/struct.OsString.html #[stable(feature = "rust1", since = "1.0.0")] @@ -201,7 +201,7 @@ pub trait OsStringExt { /// Yields the underlying byte vector of this [`OsString`]. /// - /// See the module docmentation for an example. + /// See the module documentation for an example. /// /// [`OsString`]: ../../../ffi/struct.OsString.html #[stable(feature = "rust1", since = "1.0.0")] @@ -226,14 +226,14 @@ pub trait OsStrExt { #[stable(feature = "rust1", since = "1.0.0")] /// Creates an [`OsStr`] from a byte slice. /// - /// See the module docmentation for an example. + /// See the module documentation for an example. /// /// [`OsStr`]: ../../../ffi/struct.OsStr.html fn from_bytes(slice: &[u8]) -> &Self; /// Gets the underlying byte view of the [`OsStr`] slice. /// - /// See the module docmentation for an example. + /// See the module documentation for an example. /// /// [`OsStr`]: ../../../ffi/struct.OsStr.html #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 764041d2f42..0ffa6ace2e4 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -465,12 +465,9 @@ impl Builder { } thread_info::set(imp::guard::current(), their_thread); - #[cfg(feature = "backtrace")] let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| { crate::sys_common::backtrace::__rust_begin_short_backtrace(f) })); - #[cfg(not(feature = "backtrace"))] - let try_result = panic::catch_unwind(panic::AssertUnwindSafe(f)); *their_packet.get() = Some(try_result); }; diff --git a/src/libstd/time.rs b/src/libstd/time.rs index 3bf2b8be1fe..e1ae01b602a 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -15,10 +15,10 @@ use crate::cmp; use crate::error::Error; use crate::fmt; -use crate::ops::{Add, Sub, AddAssign, SubAssign}; +use crate::ops::{Add, AddAssign, Sub, SubAssign}; use crate::sys::time; -use crate::sys_common::FromInner; use crate::sys_common::mutex::Mutex; +use crate::sys_common::FromInner; #[stable(feature = "time", since = "1.3.0")] pub use core::time::Duration; @@ -216,17 +216,17 @@ impl Instant { // * https://bugzilla.mozilla.org/show_bug.cgi?id=1487778 - a similar // Firefox bug // - // It simply seems that this it just happens so that a lot in the wild - // we're seeing panics across various platforms where consecutive calls + // It seems that this just happens a lot in the wild. + // We're seeing panics across various platforms where consecutive calls // to `Instant::now`, such as via the `elapsed` function, are panicking // as they're going backwards. Placed here is a last-ditch effort to try // to fix things up. We keep a global "latest now" instance which is // returned instead of what the OS says if the OS goes backwards. // - // To hopefully mitigate the impact of this though a few platforms are + // To hopefully mitigate the impact of this, a few platforms are // whitelisted as "these at least haven't gone backwards yet". if time::Instant::actually_monotonic() { - return Instant(os_now) + return Instant(os_now); } static LOCK: Mutex = Mutex::new(); @@ -353,8 +353,7 @@ impl Add<Duration> for Instant { /// /// [`checked_add`]: ../../std/time/struct.Instant.html#method.checked_add fn add(self, other: Duration) -> Instant { - self.checked_add(other) - .expect("overflow when adding duration to instant") + self.checked_add(other).expect("overflow when adding duration to instant") } } @@ -370,8 +369,7 @@ impl Sub<Duration> for Instant { type Output = Instant; fn sub(self, other: Duration) -> Instant { - self.checked_sub(other) - .expect("overflow when subtracting duration from instant") + self.checked_sub(other).expect("overflow when subtracting duration from instant") } } @@ -464,8 +462,7 @@ impl SystemTime { /// println!("{:?}", difference); /// ``` #[stable(feature = "time2", since = "1.8.0")] - pub fn duration_since(&self, earlier: SystemTime) - -> Result<Duration, SystemTimeError> { + pub fn duration_since(&self, earlier: SystemTime) -> Result<Duration, SystemTimeError> { self.0.sub_time(&earlier.0).map_err(SystemTimeError) } @@ -532,8 +529,7 @@ impl Add<Duration> for SystemTime { /// /// [`checked_add`]: ../../std/time/struct.SystemTime.html#method.checked_add fn add(self, dur: Duration) -> SystemTime { - self.checked_add(dur) - .expect("overflow when adding duration to instant") + self.checked_add(dur).expect("overflow when adding duration to instant") } } @@ -549,8 +545,7 @@ impl Sub<Duration> for SystemTime { type Output = SystemTime; fn sub(self, dur: Duration) -> SystemTime { - self.checked_sub(dur) - .expect("overflow when subtracting duration from instant") + self.checked_sub(dur).expect("overflow when subtracting duration from instant") } } @@ -626,7 +621,9 @@ impl SystemTimeError { #[stable(feature = "time2", since = "1.8.0")] impl Error for SystemTimeError { - fn description(&self) -> &str { "other time was not earlier than self" } + fn description(&self) -> &str { + "other time was not earlier than self" + } } #[stable(feature = "time2", since = "1.8.0")] @@ -644,17 +641,16 @@ impl FromInner<time::SystemTime> for SystemTime { #[cfg(test)] mod tests { - use super::{Instant, SystemTime, Duration, UNIX_EPOCH}; + use super::{Duration, Instant, SystemTime, UNIX_EPOCH}; macro_rules! assert_almost_eq { - ($a:expr, $b:expr) => ({ + ($a:expr, $b:expr) => {{ let (a, b) = ($a, $b); if a != b { - let (a, b) = if a > b {(a, b)} else {(b, a)}; - assert!(a - Duration::new(0, 1000) <= b, - "{:?} is not almost equal to {:?}", a, b); + let (a, b) = if a > b { (a, b) } else { (b, a) }; + assert!(a - Duration::new(0, 1000) <= b, "{:?} is not almost equal to {:?}", a, b); } - }) + }}; } #[test] @@ -729,7 +725,7 @@ mod tests { fn instant_saturating_duration_since_nopanic() { let a = Instant::now(); let ret = (a - Duration::new(1, 0)).saturating_duration_since(a); - assert_eq!(ret, Duration::new(0,0)); + assert_eq!(ret, Duration::new(0, 0)); } #[test] @@ -755,15 +751,14 @@ mod tests { let second = Duration::new(1, 0); assert_almost_eq!(a.duration_since(a - second).unwrap(), second); - assert_almost_eq!(a.duration_since(a + second).unwrap_err() - .duration(), second); + assert_almost_eq!(a.duration_since(a + second).unwrap_err().duration(), second); assert_almost_eq!(a - second + second, a); assert_almost_eq!(a.checked_sub(second).unwrap().checked_add(second).unwrap(), a); let one_second_from_epoch = UNIX_EPOCH + Duration::new(1, 0); - let one_second_from_epoch2 = UNIX_EPOCH + Duration::new(0, 500_000_000) - + Duration::new(0, 500_000_000); + let one_second_from_epoch2 = + UNIX_EPOCH + Duration::new(0, 500_000_000) + Duration::new(0, 500_000_000); assert_eq!(one_second_from_epoch, one_second_from_epoch2); // checked_add_duration will not panic on overflow |
