diff options
Diffstat (limited to 'library/std/src')
119 files changed, 1503 insertions, 1209 deletions
diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index 8ee55234cea..ae11964cb56 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -83,7 +83,7 @@ pub use alloc_crate::alloc::*; /// /// fn main() { /// let a = Box::new(4); // Allocates from the system allocator. -/// println!("{}", a); +/// println!("{a}"); /// } /// ``` /// @@ -315,7 +315,21 @@ pub fn take_alloc_error_hook() -> fn(Layout) { } fn default_alloc_error_hook(layout: Layout) { - rtprintpanic!("memory allocation of {} bytes failed\n", layout.size()); + #[cfg(not(bootstrap))] + extern "Rust" { + // This symbol is emitted by rustc next to __rust_alloc_error_handler. + // Its value depends on the -Zoom={panic,abort} compiler option. + static __rust_alloc_error_handler_should_panic: u8; + } + #[cfg(bootstrap)] + let __rust_alloc_error_handler_should_panic = 0; + + #[allow(unused_unsafe)] + if unsafe { __rust_alloc_error_handler_should_panic != 0 } { + panic!("memory allocation of {} bytes failed\n", layout.size()); + } else { + rtprintpanic!("memory allocation of {} bytes failed\n", layout.size()); + } } #[cfg(not(test))] diff --git a/library/std/src/backtrace/tests.rs b/library/std/src/backtrace/tests.rs index f5da93f93fd..4dfbf88e83e 100644 --- a/library/std/src/backtrace/tests.rs +++ b/library/std/src/backtrace/tests.rs @@ -57,10 +57,10 @@ fn test_debug() { \n { fn: \"std::rt::lang_start\", file: \"rust/rt.rs\", line: 400 },\ \n]"; - assert_eq!(format!("{:#?}", backtrace), expected); + assert_eq!(format!("{backtrace:#?}"), expected); // Format the backtrace a second time, just to make sure lazily resolved state is stable - assert_eq!(format!("{:#?}", backtrace), expected); + assert_eq!(format!("{backtrace:#?}"), expected); } #[test] @@ -91,5 +91,5 @@ fn test_frames() { let mut iter = frames.iter().zip(expected.iter()); - assert!(iter.all(|(f, e)| format!("{:#?}", f) == *e)); + assert!(iter.all(|(f, e)| format!("{f:#?}") == *e)); } diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 9e61defc31e..6b63191eb58 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -109,8 +109,8 @@ use crate::sys; /// let to_find = ["Pride and Prejudice", "Alice's Adventure in Wonderland"]; /// for &book in &to_find { /// match book_reviews.get(book) { -/// Some(review) => println!("{}: {}", book, review), -/// None => println!("{} is unreviewed.", book) +/// Some(review) => println!("{book}: {review}"), +/// None => println!("{book} is unreviewed.") /// } /// } /// @@ -119,7 +119,7 @@ use crate::sys; /// /// // Iterate over everything. /// for (book, review) in &book_reviews { -/// println!("{}: \"{}\"", book, review); +/// println!("{book}: \"{review}\""); /// } /// ``` /// @@ -199,7 +199,7 @@ use crate::sys; /// /// // Use derived implementation to print the status of the vikings. /// for (viking, health) in &vikings { -/// println!("{:?} has {} hp", viking, health); +/// println!("{viking:?} has {health} hp"); /// } /// ``` @@ -341,7 +341,7 @@ impl<K, V, S> HashMap<K, V, S> { /// ]); /// /// for key in map.keys() { - /// println!("{}", key); + /// println!("{key}"); /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -371,7 +371,7 @@ impl<K, V, S> HashMap<K, V, S> { /// assert_eq!(vec, ["a", "b", "c"]); /// ``` #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] #[stable(feature = "map_into_keys_values", since = "1.54.0")] pub fn into_keys(self) -> IntoKeys<K, V> { IntoKeys { inner: self.into_iter() } @@ -392,7 +392,7 @@ impl<K, V, S> HashMap<K, V, S> { /// ]); /// /// for val in map.values() { - /// println!("{}", val); + /// println!("{val}"); /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -419,7 +419,7 @@ impl<K, V, S> HashMap<K, V, S> { /// } /// /// for val in map.values() { - /// println!("{}", val); + /// println!("{val}"); /// } /// ``` #[stable(feature = "map_values_mut", since = "1.10.0")] @@ -449,7 +449,7 @@ impl<K, V, S> HashMap<K, V, S> { /// assert_eq!(vec, [1, 2, 3]); /// ``` #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] #[stable(feature = "map_into_keys_values", since = "1.54.0")] pub fn into_values(self) -> IntoValues<K, V> { IntoValues { inner: self.into_iter() } @@ -470,10 +470,10 @@ impl<K, V, S> HashMap<K, V, S> { /// ]); /// /// for (key, val) in map.iter() { - /// println!("key: {} val: {}", key, val); + /// println!("key: {key} val: {val}"); /// } /// ``` - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] #[stable(feature = "rust1", since = "1.0.0")] pub fn iter(&self) -> Iter<'_, K, V> { Iter { base: self.base.iter() } @@ -500,10 +500,10 @@ impl<K, V, S> HashMap<K, V, S> { /// } /// /// for (key, val) in &map { - /// println!("key: {} val: {}", key, val); + /// println!("key: {key} val: {val}"); /// } /// ``` - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] #[stable(feature = "rust1", since = "1.0.0")] pub fn iter_mut(&mut self) -> IterMut<'_, K, V> { IterMut { base: self.base.iter_mut() } @@ -547,6 +547,10 @@ impl<K, V, S> HashMap<K, V, S> { /// Clears the map, returning all key-value pairs as an iterator. Keeps the /// allocated memory for reuse. /// + /// If the returned iterator is dropped before being fully consumed, it + /// drops the remaining key-value pairs. The returned iterator keeps a + /// mutable borrow on the vector to optimize its implementation. + /// /// # Examples /// /// ``` @@ -564,7 +568,7 @@ impl<K, V, S> HashMap<K, V, S> { /// assert!(a.is_empty()); /// ``` #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] #[stable(feature = "drain", since = "1.6.0")] pub fn drain(&mut self) -> Drain<'_, K, V> { Drain { base: self.base.drain() } @@ -606,7 +610,7 @@ impl<K, V, S> HashMap<K, V, S> { /// assert_eq!(odds, vec![1, 3, 5, 7]); /// ``` #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] #[unstable(feature = "hash_drain_filter", issue = "59618")] pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, K, V, F> where @@ -617,7 +621,7 @@ impl<K, V, S> HashMap<K, V, S> { /// Retains only the elements specified by the predicate. /// - /// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)` returns `false`. + /// In other words, remove all pairs `(k, v)` for which `f(&k, &mut v)` returns `false`. /// The elements are visited in unsorted (and unspecified) order. /// /// # Examples @@ -630,7 +634,7 @@ impl<K, V, S> HashMap<K, V, S> { /// assert_eq!(map.len(), 4); /// ``` #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] #[stable(feature = "retain_hash_collection", since = "1.18.0")] pub fn retain<F>(&mut self, f: F) where @@ -1997,7 +2001,7 @@ impl<'a, K, V, S> IntoIterator for &'a HashMap<K, V, S> { type IntoIter = Iter<'a, K, V>; #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] fn into_iter(self) -> Iter<'a, K, V> { self.iter() } @@ -2009,7 +2013,7 @@ impl<'a, K, V, S> IntoIterator for &'a mut HashMap<K, V, S> { type IntoIter = IterMut<'a, K, V>; #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] fn into_iter(self) -> IterMut<'a, K, V> { self.iter_mut() } @@ -2039,7 +2043,7 @@ impl<K, V, S> IntoIterator for HashMap<K, V, S> { /// let vec: Vec<(&str, i32)> = map.into_iter().collect(); /// ``` #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] fn into_iter(self) -> IntoIter<K, V> { IntoIter { base: self.base.into_iter() } } @@ -2472,6 +2476,7 @@ impl<'a, K, V> Entry<'a, K, V> { /// # Examples /// /// ``` + /// #![feature(entry_insert)] /// use std::collections::HashMap; /// /// let mut map: HashMap<&str, String> = HashMap::new(); @@ -2480,7 +2485,7 @@ impl<'a, K, V> Entry<'a, K, V> { /// assert_eq!(entry.key(), &"poneyland"); /// ``` #[inline] - #[stable(feature = "entry_insert", since = "1.59.0")] + #[unstable(feature = "entry_insert", issue = "65225")] pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V> { match self { Occupied(mut entry) => { @@ -2814,6 +2819,7 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { /// # Examples /// /// ``` + /// #![feature(entry_insert)] /// use std::collections::HashMap; /// use std::collections::hash_map::Entry; /// @@ -2825,7 +2831,7 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { /// assert_eq!(map["poneyland"], 37); /// ``` #[inline] - #[stable(feature = "entry_insert", since = "1.59.0")] + #[unstable(feature = "entry_insert", issue = "65225")] pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V> { let base = self.base.insert_entry(value); OccupiedEntry { base } diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs index 30da22b8084..7ebc41588b3 100644 --- a/library/std/src/collections/hash/map/tests.rs +++ b/library/std/src/collections/hash/map/tests.rs @@ -515,10 +515,10 @@ fn test_show() { map.insert(1, 2); map.insert(3, 4); - let map_str = format!("{:?}", map); + let map_str = format!("{map:?}"); assert!(map_str == "{1: 2, 3: 4}" || map_str == "{3: 4, 1: 2}"); - assert_eq!(format!("{:?}", empty), "{}"); + assert_eq!(format!("{empty:?}"), "{}"); } #[test] @@ -702,7 +702,7 @@ fn test_entry_take_doesnt_corrupt() { // Test for #19292 fn check(m: &HashMap<i32, ()>) { for k in m.keys() { - assert!(m.contains_key(k), "{} is in keys() but not in the map?", k); + assert!(m.contains_key(k), "{k} is in keys() but not in the map?"); } } diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index d1450987e73..fa471a3c3f3 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -66,7 +66,7 @@ use super::map::{map_try_reserve_error, RandomState}; /// /// // Iterate over everything. /// for book in &books { -/// println!("{}", book); +/// println!("{book}"); /// } /// ``` /// @@ -91,7 +91,7 @@ use super::map::{map_try_reserve_error, RandomState}; /// /// // Use derived implementation to print the vikings. /// for x in &vikings { -/// println!("{:?}", x); +/// println!("{x:?}"); /// } /// ``` /// @@ -181,11 +181,11 @@ impl<T, S> HashSet<T, S> { /// /// // Will print in an arbitrary order. /// for x in set.iter() { - /// println!("{}", x); + /// println!("{x}"); /// } /// ``` #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] #[stable(feature = "rust1", since = "1.0.0")] pub fn iter(&self) -> Iter<'_, T> { Iter { base: self.base.iter() } @@ -227,7 +227,12 @@ impl<T, S> HashSet<T, S> { self.base.is_empty() } - /// Clears the set, returning all elements in an iterator. + /// Clears the set, returning all elements as an iterator. Keeps the + /// allocated memory for reuse. + /// + /// If the returned iterator is dropped before being fully consumed, it + /// drops the remaining elements. The returned iterator keeps a mutable + /// borrow on the vector to optimize its implementation. /// /// # Examples /// @@ -239,13 +244,13 @@ impl<T, S> HashSet<T, S> { /// /// // print 1, 2, 3 in an arbitrary order /// for i in set.drain() { - /// println!("{}", i); + /// println!("{i}"); /// } /// /// assert!(set.is_empty()); /// ``` #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] #[stable(feature = "drain", since = "1.6.0")] pub fn drain(&mut self) -> Drain<'_, T> { Drain { base: self.base.drain() } @@ -284,7 +289,7 @@ impl<T, S> HashSet<T, S> { /// assert_eq!(odds, vec![1, 3, 5, 7]); /// ``` #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] #[unstable(feature = "hash_drain_filter", issue = "59618")] pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, T, F> where @@ -295,7 +300,7 @@ impl<T, S> HashSet<T, S> { /// Retains only the elements specified by the predicate. /// - /// In other words, remove all elements `e` such that `f(&e)` returns `false`. + /// In other words, remove all elements `e` for which `f(&e)` returns `false`. /// The elements are visited in unsorted (and unspecified) order. /// /// # Examples @@ -307,7 +312,7 @@ impl<T, S> HashSet<T, S> { /// set.retain(|&k| k % 2 == 0); /// assert_eq!(set.len(), 3); /// ``` - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] #[stable(feature = "retain_hash_collection", since = "1.18.0")] pub fn retain<F>(&mut self, f: F) where @@ -520,7 +525,7 @@ where /// /// // Can be seen as `a - b`. /// for x in a.difference(&b) { - /// println!("{}", x); // Print 1 + /// println!("{x}"); // Print 1 /// } /// /// let diff: HashSet<_> = a.difference(&b).collect(); @@ -532,7 +537,7 @@ where /// assert_eq!(diff, [4].iter().collect()); /// ``` #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] #[stable(feature = "rust1", since = "1.0.0")] pub fn difference<'a>(&'a self, other: &'a HashSet<T, S>) -> Difference<'a, T, S> { Difference { iter: self.iter(), other } @@ -550,7 +555,7 @@ where /// /// // Print 1, 4 in arbitrary order. /// for x in a.symmetric_difference(&b) { - /// println!("{}", x); + /// println!("{x}"); /// } /// /// let diff1: HashSet<_> = a.symmetric_difference(&b).collect(); @@ -560,7 +565,7 @@ where /// assert_eq!(diff1, [1, 4].iter().collect()); /// ``` #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] #[stable(feature = "rust1", since = "1.0.0")] pub fn symmetric_difference<'a>( &'a self, @@ -581,14 +586,14 @@ where /// /// // Print 2, 3 in arbitrary order. /// for x in a.intersection(&b) { - /// println!("{}", x); + /// println!("{x}"); /// } /// /// let intersection: HashSet<_> = a.intersection(&b).collect(); /// assert_eq!(intersection, [2, 3].iter().collect()); /// ``` #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] #[stable(feature = "rust1", since = "1.0.0")] pub fn intersection<'a>(&'a self, other: &'a HashSet<T, S>) -> Intersection<'a, T, S> { if self.len() <= other.len() { @@ -610,14 +615,14 @@ where /// /// // Print 1, 2, 3, 4 in arbitrary order. /// for x in a.union(&b) { - /// println!("{}", x); + /// println!("{x}"); /// } /// /// let union: HashSet<_> = a.union(&b).collect(); /// assert_eq!(union, [1, 2, 3, 4].iter().collect()); /// ``` #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] #[stable(feature = "rust1", since = "1.0.0")] pub fn union<'a>(&'a self, other: &'a HashSet<T, S>) -> Union<'a, T, S> { if self.len() >= other.len() { @@ -1418,7 +1423,7 @@ impl<'a, T, S> IntoIterator for &'a HashSet<T, S> { type IntoIter = Iter<'a, T>; #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] fn into_iter(self) -> Iter<'a, T> { self.iter() } @@ -1446,11 +1451,11 @@ impl<T, S> IntoIterator for HashSet<T, S> { /// /// // Will print in an arbitrary order. /// for x in &v { - /// println!("{}", x); + /// println!("{x}"); /// } /// ``` #[inline] - #[cfg_attr(not(bootstrap), rustc_lint_query_instability)] + #[rustc_lint_query_instability] fn into_iter(self) -> IntoIter<T> { IntoIter { base: self.base.into_iter() } } diff --git a/library/std/src/collections/hash/set/tests.rs b/library/std/src/collections/hash/set/tests.rs index 6a625e6243c..233db276b9e 100644 --- a/library/std/src/collections/hash/set/tests.rs +++ b/library/std/src/collections/hash/set/tests.rs @@ -301,10 +301,10 @@ fn test_show() { set.insert(1); set.insert(2); - let set_str = format!("{:?}", set); + let set_str = format!("{set:?}"); assert!(set_str == "{1, 2}" || set_str == "{2, 1}"); - assert_eq!(format!("{:?}", empty), "{}"); + assert_eq!(format!("{empty:?}"), "{}"); } #[test] diff --git a/library/std/src/collections/mod.rs b/library/std/src/collections/mod.rs index b5e81deb480..0caec8fe05a 100644 --- a/library/std/src/collections/mod.rs +++ b/library/std/src/collections/mod.rs @@ -199,7 +199,7 @@ //! ``` //! let vec = vec![1, 2, 3, 4]; //! for x in vec.iter() { -//! println!("vec contained {}", x); +//! println!("vec contained {x:?}"); //! } //! ``` //! @@ -246,7 +246,7 @@ //! ``` //! let vec = vec![1, 2, 3, 4]; //! for x in vec.iter().rev() { -//! println!("vec contained {}", x); +//! println!("vec contained {x:?}"); //! } //! ``` //! @@ -306,7 +306,7 @@ //! //! println!("Number of occurrences of each character"); //! for (char, count) in &count { -//! println!("{}: {}", char, count); +//! println!("{char}: {count}"); //! } //! ``` //! @@ -339,7 +339,7 @@ //! // Check if they're sober enough to have another beer. //! if person.blood_alcohol > 0.3 { //! // Too drunk... for now. -//! println!("Sorry {}, I have to cut you off", id); +//! println!("Sorry {id}, I have to cut you off"); //! } else { //! // Have another! //! person.blood_alcohol += 0.1; diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 5ed9fa9d6f0..05f08c498e6 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -118,7 +118,7 @@ pub struct VarsOs { /// // We will iterate through the references to the element returned by /// // env::vars(); /// for (key, value) in env::vars() { -/// println!("{}: {}", key, value); +/// println!("{key}: {value}"); /// } /// ``` /// @@ -148,7 +148,7 @@ pub fn vars() -> Vars { /// // We will iterate through the references to the element returned by /// // env::vars_os(); /// for (key, value) in env::vars_os() { -/// println!("{:?}: {:?}", key, value); +/// println!("{key:?}: {value:?}"); /// } /// ``` #[must_use] @@ -212,8 +212,8 @@ impl fmt::Debug for VarsOs { /// /// let key = "HOME"; /// match env::var(key) { -/// Ok(val) => println!("{}: {:?}", key, val), -/// Err(e) => println!("couldn't interpret {}: {}", key, e), +/// Ok(val) => println!("{key}: {val:?}"), +/// Err(e) => println!("couldn't interpret {key}: {e}"), /// } /// ``` #[stable(feature = "env", since = "1.0.0")] @@ -252,8 +252,8 @@ fn _var(key: &OsStr) -> Result<String, VarError> { /// /// let key = "HOME"; /// match env::var_os(key) { -/// Some(val) => println!("{}: {:?}", key, val), -/// None => println!("{} is not defined in the environment.", key) +/// Some(val) => println!("{key}: {val:?}"), +/// None => println!("{key} is not defined in the environment.") /// } /// ``` #[must_use] @@ -343,7 +343,7 @@ pub fn set_var<K: AsRef<OsStr>, V: AsRef<OsStr>>(key: K, value: V) { fn _set_var(key: &OsStr, value: &OsStr) { os_imp::setenv(key, value).unwrap_or_else(|e| { - panic!("failed to set environment variable `{:?}` to `{:?}`: {}", key, value, e) + panic!("failed to set environment variable `{key:?}` to `{value:?}`: {e}") }) } @@ -385,7 +385,7 @@ pub fn remove_var<K: AsRef<OsStr>>(key: K) { fn _remove_var(key: &OsStr) { os_imp::unsetenv(key) - .unwrap_or_else(|e| panic!("failed to remove environment variable `{:?}`: {}", key, e)) + .unwrap_or_else(|e| panic!("failed to remove environment variable `{key:?}`: {e}")) } /// An iterator that splits an environment variable into paths according to @@ -421,7 +421,7 @@ pub struct SplitPaths<'a> { /// println!("'{}'", path.display()); /// } /// } -/// None => println!("{} is not defined in the environment.", key) +/// None => println!("{key} is not defined in the environment.") /// } /// ``` #[stable(feature = "env", since = "1.0.0")] @@ -684,7 +684,7 @@ pub fn temp_dir() -> PathBuf { /// match env::current_exe() { /// Ok(exe_path) => println!("Path of this executable is: {}", /// exe_path.display()), -/// Err(e) => println!("failed to get current exe path: {}", e), +/// Err(e) => println!("failed to get current exe path: {e}"), /// }; /// ``` #[stable(feature = "env", since = "1.0.0")] @@ -755,7 +755,7 @@ pub struct ArgsOs { /// /// // Prints each argument on a separate line /// for argument in env::args() { -/// println!("{}", argument); +/// println!("{argument}"); /// } /// ``` #[stable(feature = "env", since = "1.0.0")] @@ -790,7 +790,7 @@ pub fn args() -> Args { /// /// // Prints each argument on a separate line /// for argument in env::args_os() { -/// println!("{:?}", argument); +/// println!("{argument:?}"); /// } /// ``` #[stable(feature = "env", since = "1.0.0")] diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 1a96b9c9282..c3cb71a5dee 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -96,7 +96,7 @@ pub trait Error: Debug + Display { /// fn main() { /// match get_super_error() { /// Err(e) => { - /// println!("Error: {}", e); + /// println!("Error: {e}"); /// println!("Caused by: {}", e.source().unwrap()); /// } /// _ => println!("No error"), @@ -139,7 +139,7 @@ pub trait Error: Debug + Display { /// ``` /// if let Err(e) = "xc".parse::<u32>() { /// // Print `e` itself, no need for description(). - /// eprintln!("Error: {}", e); + /// eprintln!("Error: {e}"); /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -1074,7 +1074,7 @@ impl<E> Report<E> { /// /// let error = SuperError { source: SuperErrorSideKick }; /// let report = Report::new(error).pretty(true); - /// eprintln!("Error: {:?}", report); + /// eprintln!("Error: {report:?}"); /// ``` /// /// This example produces the following output: @@ -1135,7 +1135,7 @@ impl<E> Report<E> { /// let source = SuperErrorSideKick { source }; /// let error = SuperError { source }; /// let report = Report::new(error).pretty(true); - /// eprintln!("Error: {:?}", report); + /// eprintln!("Error: {report:?}"); /// ``` /// /// This example produces the following output: @@ -1210,7 +1210,7 @@ impl<E> Report<E> { /// let source = SuperErrorSideKick::new(); /// let error = SuperError { source }; /// let report = Report::new(error).pretty(true).show_backtrace(true); - /// eprintln!("Error: {:?}", report); + /// eprintln!("Error: {report:?}"); /// ``` /// /// This example produces something similar to the following output: @@ -1267,7 +1267,7 @@ where let sources = self.error.source().into_iter().flat_map(<dyn Error>::chain); for cause in sources { - write!(f, ": {}", cause)?; + write!(f, ": {cause}")?; } Ok(()) @@ -1278,7 +1278,7 @@ where fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let error = &self.error; - write!(f, "{}", error)?; + write!(f, "{error}")?; if let Some(cause) = error.source() { write!(f, "\n\nCaused by:")?; @@ -1289,9 +1289,9 @@ where writeln!(f)?; let mut indented = Indented { inner: f }; if multiple { - write!(indented, "{: >4}: {}", ind, error)?; + write!(indented, "{ind: >4}: {error}")?; } else { - write!(indented, " {}", error)?; + write!(indented, " {error}")?; } } } @@ -1333,7 +1333,7 @@ impl Report<Box<dyn Error>> { let sources = self.error.source().into_iter().flat_map(<dyn Error>::chain); for cause in sources { - write!(f, ": {}", cause)?; + write!(f, ": {cause}")?; } Ok(()) @@ -1344,7 +1344,7 @@ impl Report<Box<dyn Error>> { fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let error = &self.error; - write!(f, "{}", error)?; + write!(f, "{error}")?; if let Some(cause) = error.source() { write!(f, "\n\nCaused by:")?; @@ -1355,9 +1355,9 @@ impl Report<Box<dyn Error>> { writeln!(f)?; let mut indented = Indented { inner: f }; if multiple { - write!(indented, "{: >4}: {}", ind, error)?; + write!(indented, "{ind: >4}: {error}")?; } else { - write!(indented, " {}", error)?; + write!(indented, " {error}")?; } } } diff --git a/library/std/src/error/tests.rs b/library/std/src/error/tests.rs index eae5f43ff3c..a2a35d96ec9 100644 --- a/library/std/src/error/tests.rs +++ b/library/std/src/error/tests.rs @@ -130,7 +130,7 @@ Stack backtrace: error.backtrace = Some(trace); let report = Report::new(error).pretty(true).show_backtrace(true); - println!("Error: {}", report); + println!("Error: {report}"); assert_eq!(expected.trim_end(), report.to_string()); } @@ -155,7 +155,7 @@ Stack backtrace: let error = GenericError::new_with_source("Error with two sources", error); let report = Report::new(error).pretty(true).show_backtrace(true); - println!("Error: {}", report); + println!("Error: {report}"); assert_eq!(expected.trim_end(), report.to_string()); } @@ -355,7 +355,7 @@ Caused by: 1: The message goes on and on."; let actual = report.to_string(); - println!("{}", actual); + println!("{actual}"); assert_eq!(expected, actual); } diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs index 6e70d5ca02d..b833d0e2ca5 100644 --- a/library/std/src/ffi/c_str.rs +++ b/library/std/src/ffi/c_str.rs @@ -382,7 +382,7 @@ impl CString { let bytes: Vec<u8> = self.into(); match memchr::memchr(0, &bytes) { Some(i) => Err(NulError(i, bytes)), - None => Ok(unsafe { CString::from_vec_unchecked(bytes) }), + None => Ok(unsafe { CString::_from_vec_unchecked(bytes) }), } } } @@ -405,7 +405,7 @@ impl CString { // This allows better optimizations if lto enabled. match memchr::memchr(0, bytes) { Some(i) => Err(NulError(i, buffer)), - None => Ok(unsafe { CString::from_vec_unchecked(buffer) }), + None => Ok(unsafe { CString::_from_vec_unchecked(buffer) }), } } @@ -451,10 +451,15 @@ impl CString { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - pub unsafe fn from_vec_unchecked(mut v: Vec<u8>) -> CString { + pub unsafe fn from_vec_unchecked(v: Vec<u8>) -> Self { + debug_assert!(memchr::memchr(0, &v).is_none()); + unsafe { Self::_from_vec_unchecked(v) } + } + + unsafe fn _from_vec_unchecked(mut v: Vec<u8>) -> Self { v.reserve_exact(1); v.push(0); - CString { inner: v.into_boxed_slice() } + Self { inner: v.into_boxed_slice() } } /// Retakes ownership of a `CString` that was transferred to C via @@ -578,7 +583,7 @@ impl CString { pub fn into_string(self) -> Result<String, IntoStringError> { String::from_utf8(self.into_bytes()).map_err(|e| IntoStringError { error: e.utf8_error(), - inner: unsafe { CString::from_vec_unchecked(e.into_bytes()) }, + inner: unsafe { Self::_from_vec_unchecked(e.into_bytes()) }, }) } @@ -735,6 +740,11 @@ impl CString { #[must_use] #[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")] pub unsafe fn from_vec_with_nul_unchecked(v: Vec<u8>) -> Self { + debug_assert!(memchr::memchr(0, &v).unwrap() + 1 == v.len()); + unsafe { Self::_from_vec_with_nul_unchecked(v) } + } + + unsafe fn _from_vec_with_nul_unchecked(v: Vec<u8>) -> Self { Self { inner: v.into_boxed_slice() } } @@ -778,7 +788,7 @@ impl CString { Some(nul_pos) if nul_pos + 1 == v.len() => { // SAFETY: We know there is only one nul byte, at the end // of the vec. - Ok(unsafe { Self::from_vec_with_nul_unchecked(v) }) + Ok(unsafe { Self::_from_vec_with_nul_unchecked(v) }) } Some(nul_pos) => Err(FromVecWithNulError { error_kind: FromBytesWithNulErrorKind::InteriorNul(nul_pos), @@ -811,7 +821,7 @@ impl ops::Deref for CString { #[inline] fn deref(&self) -> &CStr { - unsafe { CStr::from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) } + unsafe { CStr::_from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) } } } @@ -928,7 +938,7 @@ impl From<Vec<NonZeroU8>> for CString { }; // SAFETY: `v` cannot contain null bytes, given the type-level // invariant of `NonZeroU8`. - CString::from_vec_unchecked(v) + Self::_from_vec_unchecked(v) } } } @@ -1110,7 +1120,7 @@ impl fmt::Display for FromBytesWithNulError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(self.description())?; if let FromBytesWithNulErrorKind::InteriorNul(pos) = self.kind { - write!(f, " at byte pos {}", pos)?; + write!(f, " at byte pos {pos}")?; } Ok(()) } @@ -1124,7 +1134,7 @@ impl fmt::Display for FromVecWithNulError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.error_kind { FromBytesWithNulErrorKind::InteriorNul(pos) => { - write!(f, "data provided contains an interior nul byte at pos {}", pos) + write!(f, "data provided contains an interior nul byte at pos {pos}") } FromBytesWithNulErrorKind::NotNulTerminated => { write!(f, "data provided is not nul terminated") @@ -1225,7 +1235,7 @@ impl CStr { unsafe { let len = sys::strlen(ptr); let ptr = ptr as *const u8; - CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1)) + Self::_from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1)) } } @@ -1268,7 +1278,7 @@ impl CStr { Some(nul_pos) if nul_pos + 1 == bytes.len() => { // SAFETY: We know there is only one nul byte, at the end // of the byte slice. - Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) }) + Ok(unsafe { Self::_from_bytes_with_nul_unchecked(bytes) }) } Some(nul_pos) => Err(FromBytesWithNulError::interior_nul(nul_pos)), None => Err(FromBytesWithNulError::not_nul_terminated()), @@ -1297,12 +1307,19 @@ impl CStr { #[stable(feature = "cstr_from_bytes", since = "1.10.0")] #[rustc_const_stable(feature = "const_cstr_unchecked", since = "1.59.0")] pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr { + // We're in a const fn, so this is the best we can do + debug_assert!(!bytes.is_empty() && bytes[bytes.len() - 1] == 0); + unsafe { Self::_from_bytes_with_nul_unchecked(bytes) } + } + + #[inline] + const unsafe fn _from_bytes_with_nul_unchecked(bytes: &[u8]) -> &Self { // SAFETY: Casting to CStr is safe because its internal representation // is a [u8] too (safe only inside std). // Dereferencing the obtained pointer is safe because it comes from a // reference. Making a reference is then safe because its lifetime // is bound by the lifetime of the given `bytes`. - unsafe { &*(bytes as *const [u8] as *const CStr) } + unsafe { &*(bytes as *const [u8] as *const Self) } } /// Returns the inner pointer to this C string. @@ -1566,7 +1583,7 @@ impl ops::Index<ops::RangeFrom<usize>> for CStr { // byte, since otherwise we could get an empty string that doesn't end // in a null. if index.start < bytes.len() { - unsafe { CStr::from_bytes_with_nul_unchecked(&bytes[index.start..]) } + unsafe { CStr::_from_bytes_with_nul_unchecked(&bytes[index.start..]) } } else { panic!( "index out of bounds: the len is {} but the index is {}", diff --git a/library/std/src/ffi/c_str/tests.rs b/library/std/src/ffi/c_str/tests.rs index 4f7ba9ad437..8d603229315 100644 --- a/library/std/src/ffi/c_str/tests.rs +++ b/library/std/src/ffi/c_str/tests.rs @@ -33,17 +33,9 @@ fn build_with_zero2() { } #[test] -fn build_with_zero3() { - unsafe { - let s = CString::from_vec_unchecked(vec![0]); - assert_eq!(s.as_bytes(), b"\0"); - } -} - -#[test] fn formatted() { let s = CString::new(&b"abc\x01\x02\n\xE2\x80\xA6\xFF"[..]).unwrap(); - assert_eq!(format!("{:?}", s), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#); + assert_eq!(format!("{s:?}"), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#); } #[test] diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs index 019b64c395e..13e3dacc30d 100644 --- a/library/std/src/ffi/mod.rs +++ b/library/std/src/ffi/mod.rs @@ -159,6 +159,15 @@ pub use self::os_str::{OsStr, OsString}; #[stable(feature = "core_c_void", since = "1.30.0")] pub use core::ffi::c_void; +#[unstable(feature = "core_ffi_c", issue = "94501")] +pub use core::ffi::{ + c_char, c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, + c_ulong, c_ulonglong, c_ushort, +}; + +#[unstable(feature = "c_size_t", issue = "88345")] +pub use core::ffi::{c_ptrdiff_t, c_size_t, c_ssize_t}; + #[unstable( feature = "c_variadic", reason = "the `c_variadic` feature has not been properly tested on \ diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 0b65336a5a7..c99d9b279a9 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -1123,7 +1123,7 @@ impl Metadata { /// let metadata = fs::metadata("foo.txt")?; /// /// if let Ok(time) = metadata.modified() { - /// println!("{:?}", time); + /// println!("{time:?}"); /// } else { /// println!("Not supported on this platform"); /// } @@ -1158,7 +1158,7 @@ impl Metadata { /// let metadata = fs::metadata("foo.txt")?; /// /// if let Ok(time) = metadata.accessed() { - /// println!("{:?}", time); + /// println!("{time:?}"); /// } else { /// println!("Not supported on this platform"); /// } @@ -1190,7 +1190,7 @@ impl Metadata { /// let metadata = fs::metadata("foo.txt")?; /// /// if let Ok(time) = metadata.created() { - /// println!("{:?}", time); + /// println!("{time:?}"); /// } else { /// println!("Not supported on this platform or filesystem"); /// } diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 16b8bf68242..6d67c396c62 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1,5 +1,6 @@ use crate::io::prelude::*; +use crate::env; use crate::fs::{self, File, OpenOptions}; use crate::io::{ErrorKind, SeekFrom}; use crate::path::Path; @@ -30,7 +31,7 @@ macro_rules! check { ($e:expr) => { match $e { Ok(t) => t, - Err(e) => panic!("{} failed with: {}", stringify!($e), e), + Err(e) => panic!("{} failed with: {e}", stringify!($e)), } }; } @@ -470,7 +471,7 @@ fn file_test_directoryinfo_readdir() { check!(fs::create_dir(dir)); let prefix = "foo"; for n in 0..3 { - let f = dir.join(&format!("{}.txt", n)); + let f = dir.join(&format!("{n}.txt")); let mut w = check!(File::create(&f)); let msg_str = format!("{}{}", prefix, n.to_string()); let msg = msg_str.as_bytes(); @@ -906,7 +907,14 @@ fn read_link() { // junction assert_eq!(check!(fs::read_link(r"C:\Users\Default User")), Path::new(r"C:\Users\Default")); // junction with special permissions - assert_eq!(check!(fs::read_link(r"C:\Documents and Settings\")), Path::new(r"C:\Users")); + // Since not all localized windows versions contain the folder "Documents and Settings" in english, + // we will briefly check, if it exists and otherwise skip the test. Except during CI we will always execute the test. + if Path::new(r"C:\Documents and Settings\").exists() || env::var_os("CI").is_some() { + assert_eq!( + check!(fs::read_link(r"C:\Documents and Settings\")), + Path::new(r"C:\Users") + ); + } } let tmpdir = tmpdir(); let link = tmpdir.join("link"); @@ -1329,7 +1337,7 @@ fn dir_entry_methods() { assert!(file.file_type().unwrap().is_file()); assert!(file.metadata().unwrap().is_file()); } - f => panic!("unknown file name: {:?}", f), + f => panic!("unknown file name: {f:?}"), } } } @@ -1340,7 +1348,7 @@ fn dir_entry_debug() { File::create(&tmpdir.join("b")).unwrap(); let mut read_dir = tmpdir.path().read_dir().unwrap(); let dir_entry = read_dir.next().unwrap().unwrap(); - let actual = format!("{:?}", dir_entry); + let actual = format!("{dir_entry:?}"); let expected = format!("DirEntry({:?})", dir_entry.0.path()); assert_eq!(actual, expected); } @@ -1409,7 +1417,7 @@ fn metadata_access_times() { || e1.kind() == ErrorKind::Unsupported && e2.kind() == ErrorKind::Unsupported => {} (a, b) => { - panic!("creation time must be always supported or not supported: {:?} {:?}", a, b,) + panic!("creation time must be always supported or not supported: {a:?} {b:?}") } } } diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs index e7eee443624..989cec976b7 100644 --- a/library/std/src/io/buffered/bufreader.rs +++ b/library/std/src/io/buffered/bufreader.rs @@ -41,7 +41,7 @@ use crate::mem::MaybeUninit; /// /// let mut line = String::new(); /// let len = reader.read_line(&mut line)?; -/// println!("First line is {} bytes long", len); +/// println!("First line is {len} bytes long"); /// Ok(()) /// } /// ``` diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index 1aa6d657889..4a50e647c64 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -141,6 +141,19 @@ struct Custom { /// It is used with the [`io::Error`] type. /// /// [`io::Error`]: Error +/// +/// # Handling errors and matching on `ErrorKind` +/// +/// In application code, use `match` for the `ErrorKind` values you are +/// expecting; use `_` to match "all other errors". +/// +/// In comprehensive and thorough tests that want to verify that a test doesn't +/// return any known incorrect error kind, you may want to cut-and-paste the +/// current full list of errors from here into your test code, and then match +/// `_` as the correct case. This seems counterintuitive, but it will make your +/// tests more robust. In particular, if you want to verify that your code does +/// produce an unrecognized error kind, the robust solution is to check for all +/// the recognized error kinds and fail in those cases. #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated)] @@ -444,7 +457,7 @@ impl From<ErrorKind> for Error { /// /// let not_found = ErrorKind::NotFound; /// let error = Error::from(not_found); - /// assert_eq!("entity not found", format!("{}", error)); + /// assert_eq!("entity not found", format!("{error}")); /// ``` #[inline] fn from(kind: ErrorKind) -> Error { @@ -548,7 +561,7 @@ impl Error { /// use std::io::Error; /// /// let os_error = Error::last_os_error(); - /// println!("last OS error: {:?}", os_error); + /// println!("last OS error: {os_error:?}"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[must_use] @@ -605,7 +618,7 @@ impl Error { /// /// fn print_os_error(err: &Error) { /// if let Some(raw_os_err) = err.raw_os_error() { - /// println!("raw OS error: {:?}", raw_os_err); + /// println!("raw OS error: {raw_os_err:?}"); /// } else { /// println!("Not an OS error"); /// } @@ -644,7 +657,7 @@ impl Error { /// /// fn print_error(err: &Error) { /// if let Some(inner_err) = err.get_ref() { - /// println!("Inner error: {:?}", inner_err); + /// println!("Inner error: {inner_err:?}"); /// } else { /// println!("No inner error"); /// } @@ -718,7 +731,7 @@ impl Error { /// /// fn print_error(err: &Error) { /// if let Some(inner_err) = err.get_ref() { - /// println!("Inner error: {}", inner_err); + /// println!("Inner error: {inner_err}"); /// } else { /// println!("No inner error"); /// } @@ -757,7 +770,7 @@ impl Error { /// /// fn print_error(err: Error) { /// if let Some(inner_err) = err.into_inner() { - /// println!("Inner error: {}", inner_err); + /// println!("Inner error: {inner_err}"); /// } else { /// println!("No inner error"); /// } @@ -839,7 +852,7 @@ impl fmt::Display for Error { match self.repr.data() { ErrorData::Os(code) => { let detail = sys::os::error_string(code); - write!(fmt, "{} (os error {})", detail, code) + write!(fmt, "{detail} (os error {code})") } ErrorData::Custom(ref c) => c.error.fmt(fmt), ErrorData::Simple(kind) => write!(fmt, "{}", kind.as_str()), diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs index 4301e941b3d..1a0538f861a 100644 --- a/library/std/src/io/error/repr_bitpacked.rs +++ b/library/std/src/io/error/repr_bitpacked.rs @@ -161,8 +161,7 @@ impl Repr { // only run in libstd's tests, unless the user uses -Zbuild-std) debug_assert!( matches!(res.data(), ErrorData::Os(c) if c == code), - "repr(os) encoding failed for {}", - code, + "repr(os) encoding failed for {code}" ); res } diff --git a/library/std/src/io/error/tests.rs b/library/std/src/io/error/tests.rs index c2c51553b20..6fd15fa8048 100644 --- a/library/std/src/io/error/tests.rs +++ b/library/std/src/io/error/tests.rs @@ -33,7 +33,7 @@ fn test_debug_error() { }}", code, kind, msg ); - assert_eq!(format!("{:?}", err), expected); + assert_eq!(format!("{err:?}"), expected); } #[test] @@ -65,8 +65,8 @@ fn test_const() { assert_eq!(E.kind(), ErrorKind::NotFound); assert_eq!(E.to_string(), "hello"); - assert!(format!("{:?}", E).contains("\"hello\"")); - assert!(format!("{:?}", E).contains("NotFound")); + assert!(format!("{E:?}").contains("\"hello\"")); + assert!(format!("{E:?}").contains("NotFound")); } #[test] @@ -101,7 +101,7 @@ fn test_simple_message_packing() { let e = &$err; // Check that the public api is right. assert_eq!(e.kind(), $kind); - assert!(format!("{:?}", e).contains($msg)); + assert!(format!("{e:?}").contains($msg)); // and we got what we expected assert_matches!( e.repr.data(), diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 71a59fb5803..cd2197fca35 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -91,7 +91,7 @@ //! // read a line into buffer //! reader.read_line(&mut buffer)?; //! -//! println!("{}", buffer); +//! println!("{buffer}"); //! Ok(()) //! } //! ``` @@ -268,8 +268,6 @@ pub use self::buffered::WriterPanicked; pub use self::stdio::set_output_capture; #[unstable(feature = "print_internals", issue = "none")] pub use self::stdio::{_eprint, _print}; -#[unstable(feature = "stdio_locked", issue = "86845")] -pub use self::stdio::{stderr_locked, stdin_locked, stdout_locked}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::{ buffered::{BufReader, BufWriter, IntoInnerError, LineWriter}, @@ -1037,7 +1035,7 @@ pub trait Read { /// fn main() -> io::Result<()> { /// let stdin = io::read_to_string(io::stdin())?; /// println!("Stdin was:"); -/// println!("{}", stdin); +/// println!("{stdin}"); /// Ok(()) /// } /// ``` @@ -1763,7 +1761,7 @@ pub trait Seek { /// .open("foo.txt").unwrap(); /// /// let hello = "Hello!\n"; - /// write!(f, "{}", hello).unwrap(); + /// write!(f, "{hello}").unwrap(); /// f.rewind().unwrap(); /// /// let mut buf = String::new(); @@ -1806,7 +1804,7 @@ pub trait Seek { /// let mut f = File::open("foo.txt")?; /// /// let len = f.stream_len()?; - /// println!("The file is currently {} bytes long", len); + /// println!("The file is currently {len} bytes long"); /// Ok(()) /// } /// ``` @@ -1990,7 +1988,7 @@ pub trait BufRead: Read { /// let buffer = stdin.fill_buf().unwrap(); /// /// // work with buffer - /// println!("{:?}", buffer); + /// println!("{buffer:?}"); /// /// // ensure the bytes we worked with aren't returned again later /// let length = buffer.len(); @@ -2044,7 +2042,7 @@ pub trait BufRead: Read { /// let mut line = String::new(); /// stdin.read_line(&mut line).unwrap(); /// // work with line - /// println!("{:?}", line); + /// println!("{line:?}"); /// } /// ``` #[unstable(feature = "buf_read_has_data_left", reason = "recently added", issue = "86423")] @@ -2112,7 +2110,8 @@ pub trait BufRead: Read { } /// Read all bytes until a newline (the `0xA` byte) is reached, and append - /// them to the provided buffer. + /// them to the provided buffer. You do not need to clear the buffer before + /// appending. /// /// This function will read bytes from the underlying stream until the /// newline delimiter (the `0xA` byte) or EOF is found. Once found, all bytes diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 3d6de20d860..50344e602a9 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -307,48 +307,6 @@ pub fn stdin() -> Stdin { } } -/// Constructs a new locked handle to the standard input of the current -/// process. -/// -/// Each handle returned is a guard granting locked access to a shared -/// global buffer whose access is synchronized via a mutex. If you need -/// more explicit control over locking, for example, in a multi-threaded -/// program, use the [`io::stdin`] function to obtain an unlocked handle, -/// along with the [`Stdin::lock`] method. -/// -/// The lock is released when the returned guard goes out of scope. The -/// returned guard also implements the [`Read`] and [`BufRead`] traits for -/// accessing the underlying data. -/// -/// **Note**: The mutex locked by this handle is not reentrant. Even in a -/// single-threaded program, calling other code that accesses [`Stdin`] -/// could cause a deadlock or panic, if this locked handle is held across -/// that call. -/// -/// ### Note: Windows Portability Consideration -/// When operating in a console, the Windows implementation of this stream does not support -/// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return -/// an error. -/// -/// # Examples -/// -/// ```no_run -/// #![feature(stdio_locked)] -/// use std::io::{self, BufRead}; -/// -/// fn main() -> io::Result<()> { -/// let mut buffer = String::new(); -/// let mut handle = io::stdin_locked(); -/// -/// handle.read_line(&mut buffer)?; -/// Ok(()) -/// } -/// ``` -#[unstable(feature = "stdio_locked", issue = "86845")] -pub fn stdin_locked() -> StdinLock<'static> { - stdin().into_locked() -} - impl Stdin { /// Locks this handle to the standard input stream, returning a readable /// guard. @@ -372,8 +330,10 @@ impl Stdin { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn lock(&self) -> StdinLock<'_> { - self.lock_any() + pub fn lock(&self) -> StdinLock<'static> { + // Locks this handle with 'static lifetime. This depends on the + // implementation detail that the underlying `Mutex` is static. + StdinLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) } } /// Locks this handle and reads a line of input, appending it to the specified buffer. @@ -389,10 +349,10 @@ impl Stdin { /// let mut input = String::new(); /// match io::stdin().read_line(&mut input) { /// Ok(n) => { - /// println!("{} bytes read", n); - /// println!("{}", input); + /// println!("{n} bytes read"); + /// println!("{input}"); /// } - /// Err(error) => println!("error: {}", error), + /// Err(error) => println!("error: {error}"), /// } /// ``` /// @@ -407,43 +367,6 @@ impl Stdin { self.lock().read_line(buf) } - // Locks this handle with any lifetime. This depends on the - // implementation detail that the underlying `Mutex` is static. - fn lock_any<'a>(&self) -> StdinLock<'a> { - StdinLock { inner: self.inner.lock().unwrap_or_else(|e| e.into_inner()) } - } - - /// Consumes this handle to the standard input stream, locking the - /// shared global buffer associated with the stream and returning a - /// readable guard. - /// - /// The lock is released when the returned guard goes out of scope. The - /// returned guard also implements the [`Read`] and [`BufRead`] traits - /// for accessing the underlying data. - /// - /// It is often simpler to directly get a locked handle using the - /// [`stdin_locked`] function instead, unless nearby code also needs to - /// use an unlocked handle. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(stdio_locked)] - /// use std::io::{self, BufRead}; - /// - /// fn main() -> io::Result<()> { - /// let mut buffer = String::new(); - /// let mut handle = io::stdin().into_locked(); - /// - /// handle.read_line(&mut buffer)?; - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "stdio_locked", issue = "86845")] - pub fn into_locked(self) -> StdinLock<'static> { - self.lock_any() - } - /// Consumes this handle and returns an iterator over input lines. /// /// For detailed semantics of this method, see the documentation on @@ -463,7 +386,7 @@ impl Stdin { #[must_use = "`self` will be dropped if the result is not used"] #[unstable(feature = "stdin_forwarders", issue = "87096")] pub fn lines(self) -> Lines<StdinLock<'static>> { - self.into_locked().lines() + self.lock().lines() } } @@ -649,42 +572,6 @@ pub fn stdout() -> Stdout { } } -/// Constructs a new locked handle to the standard output of the current -/// process. -/// -/// Each handle returned is a guard granting locked access to a shared -/// global buffer whose access is synchronized via a mutex. If you need -/// more explicit control over locking, for example, in a multi-threaded -/// program, use the [`io::stdout`] function to obtain an unlocked handle, -/// along with the [`Stdout::lock`] method. -/// -/// The lock is released when the returned guard goes out of scope. The -/// returned guard also implements the [`Write`] trait for writing data. -/// -/// ### Note: Windows Portability Consideration -/// When operating in a console, the Windows implementation of this stream does not support -/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return -/// an error. -/// -/// # Examples -/// -/// ```no_run -/// #![feature(stdio_locked)] -/// use std::io::{self, Write}; -/// -/// fn main() -> io::Result<()> { -/// let mut handle = io::stdout_locked(); -/// -/// handle.write_all(b"hello world")?; -/// -/// Ok(()) -/// } -/// ``` -#[unstable(feature = "stdio_locked", issue = "86845")] -pub fn stdout_locked() -> StdoutLock<'static> { - stdout().into_locked() -} - pub fn cleanup() { if let Some(instance) = STDOUT.get() { // Flush the data and disable buffering during shutdown @@ -712,55 +599,20 @@ impl Stdout { /// use std::io::{self, Write}; /// /// fn main() -> io::Result<()> { - /// let stdout = io::stdout(); - /// let mut handle = stdout.lock(); + /// let mut stdout = io::stdout().lock(); /// - /// handle.write_all(b"hello world")?; + /// stdout.write_all(b"hello world")?; /// /// Ok(()) /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn lock(&self) -> StdoutLock<'_> { - self.lock_any() - } - - // Locks this handle with any lifetime. This depends on the - // implementation detail that the underlying `ReentrantMutex` is - // static. - fn lock_any<'a>(&self) -> StdoutLock<'a> { + pub fn lock(&self) -> StdoutLock<'static> { + // Locks this handle with 'static lifetime. This depends on the + // implementation detail that the underlying `ReentrantMutex` is + // static. StdoutLock { inner: self.inner.lock() } } - - /// Consumes this handle to the standard output stream, locking the - /// shared global buffer associated with the stream and returning a - /// writable guard. - /// - /// The lock is released when the returned lock goes out of scope. The - /// returned guard also implements the [`Write`] trait for writing data. - /// - /// It is often simpler to directly get a locked handle using the - /// [`io::stdout_locked`] function instead, unless nearby code also - /// needs to use an unlocked handle. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(stdio_locked)] - /// use std::io::{self, Write}; - /// - /// fn main() -> io::Result<()> { - /// let mut handle = io::stdout().into_locked(); - /// - /// handle.write_all(b"hello world")?; - /// - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "stdio_locked", issue = "86845")] - pub fn into_locked(self) -> StdoutLock<'static> { - self.lock_any() - } } #[stable(feature = "std_debug", since = "1.16.0")] @@ -935,35 +787,6 @@ pub fn stderr() -> Stderr { } } -/// Constructs a new locked handle to the standard error of the current -/// process. -/// -/// This handle is not buffered. -/// -/// ### Note: Windows Portability Consideration -/// When operating in a console, the Windows implementation of this stream does not support -/// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return -/// an error. -/// -/// # Example -/// -/// ```no_run -/// #![feature(stdio_locked)] -/// use std::io::{self, Write}; -/// -/// fn main() -> io::Result<()> { -/// let mut handle = io::stderr_locked(); -/// -/// handle.write_all(b"hello world")?; -/// -/// Ok(()) -/// } -/// ``` -#[unstable(feature = "stdio_locked", issue = "86845")] -pub fn stderr_locked() -> StderrLock<'static> { - stderr().into_locked() -} - impl Stderr { /// Locks this handle to the standard error stream, returning a writable /// guard. @@ -986,43 +809,12 @@ impl Stderr { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn lock(&self) -> StderrLock<'_> { - self.lock_any() - } - - // Locks this handle with any lifetime. This depends on the - // implementation detail that the underlying `ReentrantMutex` is - // static. - fn lock_any<'a>(&self) -> StderrLock<'a> { + pub fn lock(&self) -> StderrLock<'static> { + // Locks this handle with 'static lifetime. This depends on the + // implementation detail that the underlying `ReentrantMutex` is + // static. StderrLock { inner: self.inner.lock() } } - - /// Locks and consumes this handle to the standard error stream, - /// returning a writable guard. - /// - /// The lock is released when the returned guard goes out of scope. The - /// returned guard also implements the [`Write`] trait for writing - /// data. - /// - /// # Examples - /// - /// ``` - /// #![feature(stdio_locked)] - /// use std::io::{self, Write}; - /// - /// fn foo() -> io::Result<()> { - /// let stderr = io::stderr(); - /// let mut handle = stderr.into_locked(); - /// - /// handle.write_all(b"hello world")?; - /// - /// Ok(()) - /// } - /// ``` - #[unstable(feature = "stdio_locked", issue = "86845")] - pub fn into_locked(self) -> StderrLock<'static> { - self.lock_any() - } } #[stable(feature = "std_debug", since = "1.16.0")] @@ -1161,7 +953,7 @@ where } if let Err(e) = global_s().write_fmt(args) { - panic!("failed printing to {}: {}", label, e); + panic!("failed printing to {label}: {e}"); } } diff --git a/library/std/src/io/stdio/tests.rs b/library/std/src/io/stdio/tests.rs index b1df6b7131c..f89fd27ce6c 100644 --- a/library/std/src/io/stdio/tests.rs +++ b/library/std/src/io/stdio/tests.rs @@ -50,17 +50,17 @@ fn panic_doesnt_poison() { #[test] #[cfg_attr(target_os = "emscripten", ignore)] fn test_lock_stderr() { - test_lock(stderr, stderr_locked); + test_lock(stderr, || stderr().lock()); } #[test] #[cfg_attr(target_os = "emscripten", ignore)] fn test_lock_stdin() { - test_lock(stdin, stdin_locked); + test_lock(stdin, || stdin().lock()); } #[test] #[cfg_attr(target_os = "emscripten", ignore)] fn test_lock_stdout() { - test_lock(stdout, stdout_locked); + test_lock(stdout, || stdout().lock()); } // Helper trait to make lock testing function generic. diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index 35d230eee96..542b793f6da 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -64,7 +64,7 @@ mod as_keyword {} /// } /// /// assert_eq!(last, 12); -/// println!("{}", last); +/// println!("{last}"); /// ``` /// /// A break expression is normally associated with the innermost loop enclosing the @@ -72,10 +72,10 @@ mod as_keyword {} /// ///```rust /// 'outer: for i in 1..=5 { -/// println!("outer iteration (i): {}", i); +/// println!("outer iteration (i): {i}"); /// /// '_inner: for j in 1..=200 { -/// println!(" inner iteration (j): {}", j); +/// println!(" inner iteration (j): {j}"); /// if j >= 3 { /// // breaks from inner loop, lets outer loop continue. /// break; @@ -106,7 +106,7 @@ mod as_keyword {} /// }; /// // first number in Fibonacci sequence over 10: /// assert_eq!(result, 13); -/// println!("{}", result); +/// println!("{result}"); /// ``` /// /// For more details consult the [Reference on "break expression"] and the [Reference on "break and @@ -200,7 +200,7 @@ mod const_keyword {} /// if number % 2 == 0 { /// continue; /// } -/// println!("{}", number); +/// println!("{number}"); /// } ///``` /// @@ -515,7 +515,7 @@ mod fn_keyword {} /// } /// /// for i in std::iter::repeat(5) { -/// println!("turns out {} never stops being 5", i); +/// println!("turns out {i} never stops being 5"); /// break; // would loop forever otherwise /// } /// @@ -776,7 +776,7 @@ mod in_keyword {} /// let shadowing_example = true; /// let shadowing_example = 123.4; /// let shadowing_example = shadowing_example as u32; -/// let mut shadowing_example = format!("cool! {}", shadowing_example); +/// let mut shadowing_example = format!("cool! {shadowing_example}"); /// shadowing_example += " something else!"; // not shadowing /// ``` /// @@ -805,7 +805,7 @@ mod let_keyword {} /// let mut counter = 0; /// /// while counter < 10 { -/// println!("{}", counter); +/// println!("{counter}"); /// counter += 1; /// } /// ``` @@ -836,7 +836,7 @@ mod let_keyword {} /// if i == 10 { /// counter = None; /// } else { -/// println!("{}", i); +/// println!("{i}"); /// counter = Some (i + 1); /// } /// } @@ -866,7 +866,7 @@ mod while_keyword {} /// /// let mut i = 1; /// loop { -/// println!("i is {}", i); +/// println!("i is {i}"); /// if i > 100 { /// break; /// } @@ -920,8 +920,8 @@ mod loop_keyword {} /// /// let a_number = Option::Some(10); /// match a_number { -/// Some(x) if x <= 5 => println!("0 to 5 num = {}", x), -/// Some(x @ 6..=10) => println!("6 to 10 num = {}", x), +/// Some(x) if x <= 5 => println!("0 to 5 num = {x}"), +/// Some(x @ 6..=10) => println!("6 to 10 num = {x}"), /// None => panic!(), /// // all other numbers /// _ => panic!(), @@ -940,8 +940,8 @@ mod loop_keyword {} /// /// let get_inner = Outer::Double(None, Some(String::new())); /// match get_inner { -/// Outer::Double(None, Some(st)) => println!("{}", st), -/// Outer::Single(opt) => println!("{:?}", opt), +/// Outer::Double(None, Some(st)) => println!("{st}"), +/// Outer::Single(opt) => println!("{opt:?}"), /// _ => panic!(), /// } /// ``` @@ -988,7 +988,7 @@ mod mod_keyword {} /// /// ```rust /// let data = vec![1, 2, 3]; -/// let closure = move || println!("captured {:?} by value", data); +/// let closure = move || println!("captured {data:?} by value"); /// /// // data is no longer available, it is owned by the closure /// ``` @@ -1001,7 +1001,7 @@ mod mod_keyword {} /// ```rust /// fn create_fn() -> impl Fn() { /// let text = "Fn".to_owned(); -/// move || println!("This is a: {}", text) +/// move || println!("This is a: {text}") /// } /// /// let fn_plain = create_fn(); @@ -1014,7 +1014,7 @@ mod mod_keyword {} /// let data = vec![1, 2, 3]; /// /// std::thread::spawn(move || { -/// println!("captured {:?} by value", data) +/// println!("captured {data:?} by value") /// }).join().unwrap(); /// /// // data was moved to the spawned thread, so we cannot use it here @@ -1025,7 +1025,7 @@ mod mod_keyword {} /// ```rust /// let capture = "hello".to_owned(); /// let block = async move { -/// println!("rust says {} from async block", capture); +/// println!("rust says {capture} from async block"); /// }; /// ``` /// @@ -1124,7 +1124,7 @@ mod pub_keyword {} /// let maybe_name = Some(String::from("Alice")); /// // The variable 'maybe_name' is consumed here ... /// match maybe_name { -/// Some(n) => println!("Hello, {}", n), +/// Some(n) => println!("Hello, {n}"), /// _ => println!("Hello, world"), /// } /// // ... and is now unavailable. @@ -1138,7 +1138,7 @@ mod pub_keyword {} /// let maybe_name = Some(String::from("Alice")); /// // Using `ref`, the value is borrowed, not moved ... /// match maybe_name { -/// Some(ref n) => println!("Hello, {}", n), +/// Some(ref n) => println!("Hello, {n}"), /// _ => println!("Hello, world"), /// } /// // ... so it's available here! @@ -1423,7 +1423,7 @@ mod self_upper_keyword {} /// // With a strictly read-only static, references will have the same address /// assert_eq!(r1, r2); /// // A static item can be used just like a variable in many cases -/// println!("{:?}", FOO); +/// println!("{FOO:?}"); /// ``` /// /// # Mutable `static`s @@ -1675,7 +1675,7 @@ mod super_keyword {} /// # #![allow(dead_code)] /// fn debug_iter<I: Iterator>(it: I) where I::Item: std::fmt::Debug { /// for elem in it { -/// println!("{:#?}", elem); +/// println!("{elem:#?}"); /// } /// } /// @@ -2203,17 +2203,18 @@ mod where_keyword {} /// /// Use `async` in front of `fn`, `closure`, or a `block` to turn the marked code into a `Future`. /// As such the code will not be run immediately, but will only be evaluated when the returned -/// future is `.await`ed. +/// future is [`.await`]ed. /// -/// We have written an [async book] detailing async/await and trade-offs compared to using threads. +/// We have written an [async book] detailing `async`/`await` and trade-offs compared to using threads. /// /// ## Editions /// /// `async` is a keyword from the 2018 edition onwards. /// -/// It is available for use in stable rust from version 1.39 onwards. +/// It is available for use in stable Rust from version 1.39 onwards. /// /// [`Future`]: future::Future +/// [`.await`]: ../std/keyword.await.html /// [async book]: https://rust-lang.github.io/async-book/ mod async_keyword {} @@ -2221,19 +2222,20 @@ mod async_keyword {} // /// Suspend execution until the result of a [`Future`] is ready. /// -/// `.await`ing a future will suspend the current function's execution until the `executor` +/// `.await`ing a future will suspend the current function's execution until the executor /// has run the future to completion. /// -/// Read the [async book] for details on how async/await and executors work. +/// Read the [async book] for details on how [`async`]/`await` and executors work. /// /// ## Editions /// /// `await` is a keyword from the 2018 edition onwards. /// -/// It is available for use in stable rust from version 1.39 onwards. +/// It is available for use in stable Rust from version 1.39 onwards. /// /// [`Future`]: future::Future /// [async book]: https://rust-lang.github.io/async-book/ +/// [`async`]: ../std/keyword.async.html mod await_keyword {} #[doc(keyword = "dyn")] @@ -2311,7 +2313,7 @@ mod dyn_keyword {} /// match u { /// IntOrFloat { i: 10 } => println!("Found exactly ten!"), /// // Matching the field `f` provides an `f32`. -/// IntOrFloat { f } => println!("Found f = {} !", f), +/// IntOrFloat { f } => println!("Found f = {f} !"), /// } /// } /// ``` @@ -2335,7 +2337,7 @@ mod dyn_keyword {} /// let i = unsafe { &mut u.i }; /// /// *i = 10; -/// println!("f = {} and i = {}", f, i); +/// println!("f = {f} and i = {i}"); /// ``` /// /// See the [Reference][union] for more informations on `union`s. diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index a03da0682a5..a464f2d4c74 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -212,7 +212,6 @@ #![needs_panic_runtime] // std may use features in a platform-specific way #![allow(unused_features)] -#![feature(rustc_allow_const_fn_unstable)] #![cfg_attr(test, feature(internal_output_capture, print_internals, update_panic_count))] #![cfg_attr( all(target_vendor = "fortanix", target_env = "sgx"), @@ -222,46 +221,41 @@ // std is implemented with unstable features, many of which are internal // compiler details that will never be stable // NB: the following list is sorted to minimize merge conflicts. -#![feature(absolute_path)] #![feature(alloc_error_handler)] #![feature(alloc_layout_extra)] #![feature(allocator_api)] #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] #![feature(allow_internal_unstable)] -#![feature(arbitrary_self_types)] #![feature(array_error_internals)] #![feature(assert_matches)] #![feature(associated_type_bounds)] -#![feature(async_stream)] +#![feature(async_iterator)] #![feature(atomic_mut_ptr)] -#![feature(auto_traits)] #![feature(bench_black_box)] -#![feature(bool_to_option)] #![feature(box_syntax)] #![feature(c_unwind)] #![feature(c_variadic)] #![feature(cfg_accessible)] #![feature(cfg_eval)] -#![cfg_attr(bootstrap, feature(cfg_target_has_atomic))] #![feature(cfg_target_thread_local)] #![feature(char_error_internals)] #![feature(char_internals)] #![feature(concat_bytes)] #![feature(concat_idents)] -#![feature(const_fn_floating_point_arithmetic)] -#![feature(const_fn_fn_ptr_basics)] -#![feature(const_fn_trait_bound)] +#![cfg_attr(bootstrap, feature(const_fn_fn_ptr_basics))] +#![cfg_attr(bootstrap, feature(const_fn_trait_bound))] #![feature(const_format_args)] #![feature(const_io_structs)] #![feature(const_ip)] #![feature(const_ipv4)] #![feature(const_ipv6)] -#![feature(const_option)] #![feature(const_mut_refs)] +#![feature(const_option)] #![feature(const_socketaddr)] #![feature(const_trait_impl)] -#![feature(container_error_extra)] +#![feature(c_size_t)] +#![feature(core_ffi_c)] #![feature(core_intrinsics)] #![feature(core_panic)] #![feature(custom_test_frameworks)] @@ -269,6 +263,7 @@ #![feature(doc_cfg)] #![feature(doc_cfg_hide)] #![feature(rustdoc_internals)] +#![cfg_attr(not(bootstrap), feature(deprecated_suggestion))] #![feature(doc_masked)] #![feature(doc_notable_trait)] #![feature(dropck_eyepatch)] @@ -278,24 +273,17 @@ #![feature(exact_size_is_empty)] #![feature(exhaustive_patterns)] #![feature(extend_one)] -#![feature(fn_traits)] #![feature(float_minimum_maximum)] #![feature(format_args_nl)] -#![feature(gen_future)] -#![feature(generator_trait)] #![feature(get_mut_unchecked)] #![feature(hashmap_internals)] #![feature(int_error_internals)] -#![feature(integer_atomics)] -#![feature(int_log)] -#![feature(into_future)] #![feature(intra_doc_pointers)] #![feature(lang_items)] #![feature(linkage)] #![feature(log_syntax)] #![feature(map_try_insert)] #![feature(maybe_uninit_slice)] -#![feature(maybe_uninit_uninit_array)] #![feature(maybe_uninit_write_slice)] #![feature(min_specialization)] #![feature(mixed_integer_ops)] @@ -311,23 +299,18 @@ #![feature(panic_internals)] #![feature(panic_can_unwind)] #![feature(panic_unwind)] -#![feature(pin_static_ref)] #![feature(platform_intrinsics)] #![feature(portable_simd)] #![feature(prelude_import)] #![feature(ptr_as_uninit)] -#![feature(ptr_internals)] +#![feature(raw_os_nonzero)] #![feature(rustc_attrs)] -#![feature(rustc_private)] #![feature(saturating_int_impl)] -#![feature(slice_concat_ext)] #![feature(slice_internals)] #![feature(slice_ptr_get)] -#![feature(slice_ptr_len)] #![feature(staged_api)] #![feature(std_internals)] #![feature(stdsimd)] -#![feature(stmt_expr_attributes)] #![feature(str_internals)] #![feature(test)] #![feature(thread_local)] @@ -337,8 +320,6 @@ #![feature(trace_macros)] #![feature(try_blocks)] #![feature(try_reserve_kind)] -#![feature(unboxed_closures)] -#![feature(unwrap_infallible)] #![feature(vec_into_raw_parts)] // NB: the above list is sorted to minimize merge conflicts. #![default_lib_allocator] @@ -365,6 +346,11 @@ extern crate libc; #[allow(unused_extern_crates)] extern crate unwind; +#[doc(masked)] +#[allow(unused_extern_crates)] +#[cfg(feature = "miniz_oxide")] +extern crate miniz_oxide; + // During testing, this crate is not actually the "real" std library, but rather // it links to the real std library, which was compiled from this same source // code. So any lang items std defines are conditionally excluded (or else they @@ -378,6 +364,11 @@ extern crate std as realstd; #[macro_use] mod macros; +// The runtime entry point and a few unstable public functions used by the +// compiler +#[macro_use] +pub mod rt; + // The Rust prelude pub mod prelude; @@ -404,6 +395,8 @@ pub use alloc_crate::vec; pub use core::any; #[stable(feature = "core_array", since = "1.36.0")] pub use core::array; +#[unstable(feature = "async_iterator", issue = "79024")] +pub use core::async_iter; #[stable(feature = "rust1", since = "1.0.0")] pub use core::cell; #[stable(feature = "rust1", since = "1.0.0")] @@ -458,8 +451,6 @@ pub use core::pin; pub use core::ptr; #[stable(feature = "rust1", since = "1.0.0")] pub use core::result; -#[unstable(feature = "async_stream", issue = "79024")] -pub use core::stream; #[stable(feature = "i128", since = "1.26.0")] #[allow(deprecated, deprecated_in_future)] pub use core::u128; @@ -510,10 +501,8 @@ pub mod lazy; #[allow(missing_debug_implementations, dead_code, unsafe_op_in_unsafe_fn, unused_unsafe)] #[allow(rustdoc::bare_urls)] #[unstable(feature = "portable_simd", issue = "86656")] -#[cfg(not(all(miri, doctest)))] // Miri does not support all SIMD intrinsics mod std_float; -#[cfg(not(all(miri, doctest)))] // Miri does not support all SIMD intrinsics #[doc = include_str!("../../portable-simd/crates/core_simd/src/core_simd_docs.md")] #[unstable(feature = "portable_simd", issue = "86656")] pub mod simd { @@ -562,11 +551,6 @@ pub mod arch { #[stable(feature = "simd_x86", since = "1.27.0")] pub use std_detect::is_x86_feature_detected; -// The runtime entry point and a few unstable public functions used by the -// compiler -#[macro_use] -pub mod rt; - // Platform-abstraction modules mod sys; mod sys_common; diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs index 23cbfaeef48..c597fb5df45 100644 --- a/library/std/src/macros.rs +++ b/library/std/src/macros.rs @@ -60,7 +60,9 @@ macro_rules! panic { #[cfg_attr(not(test), rustc_diagnostic_item = "print_macro")] #[allow_internal_unstable(print_internals)] macro_rules! print { - ($($arg:tt)*) => ($crate::io::_print($crate::format_args!($($arg)*))); + ($($arg:tt)*) => { + $crate::io::_print($crate::format_args!($($arg)*)) + }; } /// Prints to the standard output, with a newline. @@ -94,10 +96,12 @@ macro_rules! print { #[cfg_attr(not(test), rustc_diagnostic_item = "println_macro")] #[allow_internal_unstable(print_internals, format_args_nl)] macro_rules! println { - () => ($crate::print!("\n")); - ($($arg:tt)*) => ({ - $crate::io::_print($crate::format_args_nl!($($arg)*)); - }) + () => { + $crate::print!("\n") + }; + ($($arg:tt)*) => { + $crate::io::_print($crate::format_args_nl!($($arg)*)) + }; } /// Prints to the standard error. @@ -126,7 +130,9 @@ macro_rules! println { #[cfg_attr(not(test), rustc_diagnostic_item = "eprint_macro")] #[allow_internal_unstable(print_internals)] macro_rules! eprint { - ($($arg:tt)*) => ($crate::io::_eprint($crate::format_args!($($arg)*))); + ($($arg:tt)*) => { + $crate::io::_eprint($crate::format_args!($($arg)*)) + }; } /// Prints to the standard error, with a newline. @@ -155,10 +161,12 @@ macro_rules! eprint { #[cfg_attr(not(test), rustc_diagnostic_item = "eprintln_macro")] #[allow_internal_unstable(print_internals, format_args_nl)] macro_rules! eprintln { - () => ($crate::eprint!("\n")); - ($($arg:tt)*) => ({ - $crate::io::_eprint($crate::format_args_nl!($($arg)*)); - }) + () => { + $crate::eprint!("\n") + }; + ($($arg:tt)*) => { + $crate::io::_eprint($crate::format_args_nl!($($arg)*)) + }; } /// Prints and returns the value of a given expression for quick and dirty diff --git a/library/std/src/net/addr/tests.rs b/library/std/src/net/addr/tests.rs index 40f5a84bcd5..585a17451a0 100644 --- a/library/std/src/net/addr/tests.rs +++ b/library/std/src/net/addr/tests.rs @@ -169,30 +169,30 @@ fn is_v6() { fn socket_v4_to_str() { let socket = SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 8080); - assert_eq!(format!("{}", socket), "192.168.0.1:8080"); - assert_eq!(format!("{:<20}", socket), "192.168.0.1:8080 "); - assert_eq!(format!("{:>20}", socket), " 192.168.0.1:8080"); - assert_eq!(format!("{:^20}", socket), " 192.168.0.1:8080 "); - assert_eq!(format!("{:.10}", socket), "192.168.0."); + assert_eq!(format!("{socket}"), "192.168.0.1:8080"); + assert_eq!(format!("{socket:<20}"), "192.168.0.1:8080 "); + assert_eq!(format!("{socket:>20}"), " 192.168.0.1:8080"); + assert_eq!(format!("{socket:^20}"), " 192.168.0.1:8080 "); + assert_eq!(format!("{socket:.10}"), "192.168.0."); } #[test] fn socket_v6_to_str() { let mut socket = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53, 0, 0); - assert_eq!(format!("{}", socket), "[2a02:6b8:0:1::1]:53"); - assert_eq!(format!("{:<24}", socket), "[2a02:6b8:0:1::1]:53 "); - assert_eq!(format!("{:>24}", socket), " [2a02:6b8:0:1::1]:53"); - assert_eq!(format!("{:^24}", socket), " [2a02:6b8:0:1::1]:53 "); - assert_eq!(format!("{:.15}", socket), "[2a02:6b8:0:1::"); + assert_eq!(format!("{socket}"), "[2a02:6b8:0:1::1]:53"); + assert_eq!(format!("{socket:<24}"), "[2a02:6b8:0:1::1]:53 "); + assert_eq!(format!("{socket:>24}"), " [2a02:6b8:0:1::1]:53"); + assert_eq!(format!("{socket:^24}"), " [2a02:6b8:0:1::1]:53 "); + assert_eq!(format!("{socket:.15}"), "[2a02:6b8:0:1::"); socket.set_scope_id(5); - assert_eq!(format!("{}", socket), "[2a02:6b8:0:1::1%5]:53"); - assert_eq!(format!("{:<24}", socket), "[2a02:6b8:0:1::1%5]:53 "); - assert_eq!(format!("{:>24}", socket), " [2a02:6b8:0:1::1%5]:53"); - assert_eq!(format!("{:^24}", socket), " [2a02:6b8:0:1::1%5]:53 "); - assert_eq!(format!("{:.18}", socket), "[2a02:6b8:0:1::1%5"); + assert_eq!(format!("{socket}"), "[2a02:6b8:0:1::1%5]:53"); + assert_eq!(format!("{socket:<24}"), "[2a02:6b8:0:1::1%5]:53 "); + assert_eq!(format!("{socket:>24}"), " [2a02:6b8:0:1::1%5]:53"); + assert_eq!(format!("{socket:^24}"), " [2a02:6b8:0:1::1%5]:53 "); + assert_eq!(format!("{socket:.18}"), "[2a02:6b8:0:1::1%5"); } #[test] diff --git a/library/std/src/net/mod.rs b/library/std/src/net/mod.rs index f676e0a04f0..9ed4a98f943 100644 --- a/library/std/src/net/mod.rs +++ b/library/std/src/net/mod.rs @@ -14,6 +14,10 @@ //! * [`ToSocketAddrs`] is a trait that used for generic address resolution when interacting //! with networking objects like [`TcpListener`], [`TcpStream`] or [`UdpSocket`] //! * Other types are return or parameter types for various methods in this module +//! +//! Rust disables inheritance of socket objects to child processes by default when possible. For +//! example, through the use of the `CLOEXEC` flag in UNIX systems or the `HANDLE_FLAG_INHERIT` +//! flag on Windows. #![stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index cc4e4fd4fdc..f5d3c4905e0 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -595,10 +595,10 @@ impl TcpStream { /// // via platform-specific APIs such as epoll or IOCP /// wait_for_fd(); /// } - /// Err(e) => panic!("encountered IO error: {}", e), + /// Err(e) => panic!("encountered IO error: {e}"), /// }; /// }; - /// println!("bytes: {:?}", buf); + /// println!("bytes: {buf:?}"); /// ``` #[stable(feature = "net2_mutators", since = "1.9.0")] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { @@ -799,8 +799,8 @@ impl TcpListener { /// /// let listener = TcpListener::bind("127.0.0.1:8080").unwrap(); /// match listener.accept() { - /// Ok((_socket, addr)) => println!("new client: {:?}", addr), - /// Err(e) => println!("couldn't get client: {:?}", e), + /// Ok((_socket, addr)) => println!("new client: {addr:?}"), + /// Err(e) => println!("couldn't get client: {e:?}"), /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -991,7 +991,7 @@ impl TcpListener { /// wait_for_fd(); /// continue; /// } - /// Err(e) => panic!("encountered IO error: {}", e), + /// Err(e) => panic!("encountered IO error: {e}"), /// } /// } /// ``` diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs index c2061c13512..8c0adcfb0eb 100644 --- a/library/std/src/net/tcp/tests.rs +++ b/library/std/src/net/tcp/tests.rs @@ -142,8 +142,7 @@ fn write_close() { e.kind() == ErrorKind::ConnectionReset || e.kind() == ErrorKind::BrokenPipe || e.kind() == ErrorKind::ConnectionAborted, - "unknown error: {}", - e + "unknown error: {e}" ); } } @@ -508,7 +507,7 @@ fn close_readwrite_smoke() { } #[test] -#[cfg(unix)] // test doesn't work on Windows, see #31657 +#[cfg_attr(target_env = "sgx", ignore)] fn close_read_wakes_up() { each_ip(&mut |addr| { let a = t!(TcpListener::bind(&addr)); @@ -655,7 +654,7 @@ fn debug() { inner_name, render_inner(&listener) ); - assert_eq!(format!("{:?}", listener), compare); + assert_eq!(format!("{listener:?}"), compare); let stream = t!(TcpStream::connect(&("localhost", socket_addr.port()))); let compare = format!( @@ -665,7 +664,7 @@ fn debug() { inner_name, render_inner(&stream) ); - assert_eq!(format!("{:?}", stream), compare); + assert_eq!(format!("{stream:?}"), compare); } // FIXME: re-enabled openbsd tests once their socket timeout code @@ -832,7 +831,7 @@ fn set_nonblocking() { match stream.read(&mut buf) { Ok(_) => panic!("expected error"), Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} - Err(e) => panic!("unexpected error {}", e), + Err(e) => panic!("unexpected error {e}"), } } @@ -862,7 +861,7 @@ fn peek() { match c.peek(&mut b) { Ok(_) => panic!("expected error"), Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} - Err(e) => panic!("unexpected error {}", e), + Err(e) => panic!("unexpected error {e}"), } t!(txdone.send(())); }) diff --git a/library/std/src/net/udp.rs b/library/std/src/net/udp.rs index 11a696e92c8..864e1b0f345 100644 --- a/library/std/src/net/udp.rs +++ b/library/std/src/net/udp.rs @@ -605,9 +605,9 @@ impl UdpSocket { /// /// let socket = UdpSocket::bind("127.0.0.1:34254").expect("couldn't bind to address"); /// match socket.take_error() { - /// Ok(Some(error)) => println!("UdpSocket error: {:?}", error), + /// Ok(Some(error)) => println!("UdpSocket error: {error:?}"), /// Ok(None) => println!("No error"), - /// Err(error) => println!("UdpSocket.take_error failed: {:?}", error), + /// Err(error) => println!("UdpSocket.take_error failed: {error:?}"), /// } /// ``` #[stable(feature = "net2_mutators", since = "1.9.0")] @@ -686,8 +686,8 @@ impl UdpSocket { /// socket.connect("127.0.0.1:8080").expect("connect function failed"); /// let mut buf = [0; 10]; /// match socket.recv(&mut buf) { - /// Ok(received) => println!("received {} bytes {:?}", received, &buf[..received]), - /// Err(e) => println!("recv function failed: {:?}", e), + /// Ok(received) => println!("received {received} bytes {:?}", &buf[..received]), + /// Err(e) => println!("recv function failed: {e:?}"), /// } /// ``` #[stable(feature = "net2_mutators", since = "1.9.0")] @@ -726,8 +726,8 @@ impl UdpSocket { /// socket.connect("127.0.0.1:8080").expect("connect function failed"); /// let mut buf = [0; 10]; /// match socket.peek(&mut buf) { - /// Ok(received) => println!("received {} bytes", received), - /// Err(e) => println!("peek function failed: {:?}", e), + /// Ok(received) => println!("received {received} bytes"), + /// Err(e) => println!("peek function failed: {e:?}"), /// } /// ``` #[stable(feature = "peek", since = "1.18.0")] @@ -770,7 +770,7 @@ impl UdpSocket { /// // via platform-specific APIs such as epoll or IOCP /// wait_for_fd(); /// } - /// Err(e) => panic!("encountered IO error: {}", e), + /// Err(e) => panic!("encountered IO error: {e}"), /// } /// }; /// println!("bytes: {:?}", &buf[..num_bytes_read]); diff --git a/library/std/src/net/udp/tests.rs b/library/std/src/net/udp/tests.rs index a51113dd9e7..f82904ffbbf 100644 --- a/library/std/src/net/udp/tests.rs +++ b/library/std/src/net/udp/tests.rs @@ -173,8 +173,8 @@ fn debug() { let udpsock = t!(UdpSocket::bind(&socket_addr)); let udpsock_inner = udpsock.0.socket().as_raw(); - let compare = format!("UdpSocket {{ addr: {:?}, {}: {:?} }}", socket_addr, name, udpsock_inner); - assert_eq!(format!("{:?}", udpsock), compare); + let compare = format!("UdpSocket {{ addr: {socket_addr:?}, {name}: {udpsock_inner:?} }}"); + assert_eq!(format!("{udpsock:?}"), compare); } // FIXME: re-enabled openbsd/netbsd tests once their socket timeout code @@ -359,7 +359,7 @@ fn set_nonblocking() { match socket.recv(&mut buf) { Ok(_) => panic!("expected error"), Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} - Err(e) => panic!("unexpected error {}", e), + Err(e) => panic!("unexpected error {e}"), } }) } diff --git a/library/std/src/os/fd/mod.rs b/library/std/src/os/fd/mod.rs index df11dc21aa7..13bb079194f 100644 --- a/library/std/src/os/fd/mod.rs +++ b/library/std/src/os/fd/mod.rs @@ -11,3 +11,6 @@ pub mod owned; // Implementations for `AsRawFd` etc. for network types. mod net; + +#[cfg(test)] +mod tests; diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index 71c660e7186..807b057234a 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -8,7 +8,7 @@ use crate::fmt; use crate::fs; use crate::marker::PhantomData; use crate::mem::forget; -#[cfg(not(target_os = "wasi"))] +#[cfg(not(any(target_os = "wasi", target_env = "sgx")))] use crate::sys::cvt; use crate::sys_common::{AsInner, FromInner, IntoInner}; @@ -21,6 +21,10 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; /// descriptor, so it can be used in FFI in places where a file descriptor is /// passed as an argument, it is not captured or consumed, and it never has the /// value `-1`. +/// +/// This type's `.to_owned()` implementation returns another `BorrowedFd` +/// rather than an `OwnedFd`. It just makes a trivial copy of the raw file +/// descriptor, which is then borrowed under the same lifetime. #[derive(Copy, Clone)] #[repr(transparent)] #[rustc_layout_scalar_valid_range_start(0)] @@ -62,7 +66,7 @@ impl BorrowedFd<'_> { /// the returned `BorrowedFd`, and it must not have the value `-1`. #[inline] #[unstable(feature = "io_safety", issue = "87074")] - pub unsafe fn borrow_raw_fd(fd: RawFd) -> Self { + pub unsafe fn borrow_raw(fd: RawFd) -> Self { assert_ne!(fd, u32::MAX as RawFd); // SAFETY: we just asserted that the value is in the valid range and isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned) unsafe { Self { fd, _phantom: PhantomData } } @@ -231,7 +235,7 @@ impl AsFd for OwnedFd { // Safety: `OwnedFd` and `BorrowedFd` have the same validity // invariants, and the `BorrowdFd` is bounded by the lifetime // of `&self`. - unsafe { BorrowedFd::borrow_raw_fd(self.as_raw_fd()) } + unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) } } } diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs index f874cf0b42d..f9c883dd6bf 100644 --- a/library/std/src/os/fd/raw.rs +++ b/library/std/src/os/fd/raw.rs @@ -5,6 +5,8 @@ use crate::fs; use crate::io; use crate::os::raw; +#[cfg(doc)] +use crate::os::unix::io::AsFd; #[cfg(unix)] use crate::os::unix::io::OwnedFd; #[cfg(target_os = "wasi")] @@ -24,9 +26,14 @@ pub type RawFd = raw::c_int; pub trait AsRawFd { /// Extracts the raw file descriptor. /// - /// This method does **not** pass ownership of the raw file descriptor - /// to the caller. The descriptor is only guaranteed to be valid while - /// the original object has not yet been destroyed. + /// This function is typically used to **borrow** an owned file descriptor. + /// When used in this way, this method does **not** pass ownership of the + /// raw file descriptor to the caller, and the file descriptor is only + /// guaranteed to be valid while the original object has not yet been + /// destroyed. + /// + /// However, borrowing is not strictly required. See [`AsFd::as_fd`] + /// for an API which strictly borrows a file descriptor. /// /// # Example /// @@ -55,15 +62,18 @@ pub trait FromRawFd { /// Constructs a new instance of `Self` from the given raw file /// descriptor. /// - /// This function **consumes ownership** of the specified file - /// descriptor. The returned object will take responsibility for closing - /// it when the object goes out of scope. + /// This function is typically used to **consume ownership** of the + /// specified file descriptor. When used in this way, the returned object + /// will take responsibility for closing it when the object goes out of + /// scope. + /// + /// However, consuming ownership is not strictly required. Use a + /// [`From<OwnedFd>::from`] implementation for an API which strictly + /// consumes ownership. /// - /// This function is also unsafe as the primitives currently returned - /// have the contract that they are the sole owner of the file - /// descriptor they are wrapping. Usage of this function could - /// accidentally allow violating this contract which can cause memory - /// unsafety in code that relies on it being true. + /// # Safety + /// + /// The `fd` passed in must be a valid an open file descriptor. /// /// # Example /// @@ -94,9 +104,13 @@ pub trait FromRawFd { pub trait IntoRawFd { /// Consumes this object, returning the raw underlying file descriptor. /// - /// This function **transfers ownership** of the underlying file descriptor - /// to the caller. Callers are then the unique owners of the file descriptor - /// and must close the descriptor once it's no longer needed. + /// This function is typically used to **transfer ownership** of the underlying + /// file descriptor to the caller. When used in this way, callers are then the unique + /// owners of the file descriptor and must close it once it's no longer needed. + /// + /// However, transferring ownership is not strictly required. Use a + /// [`Into<OwnedFd>::into`] implementation for an API which strictly + /// transfers ownership. /// /// # Example /// diff --git a/library/std/src/os/fd/tests.rs b/library/std/src/os/fd/tests.rs new file mode 100644 index 00000000000..26ef93e3d71 --- /dev/null +++ b/library/std/src/os/fd/tests.rs @@ -0,0 +1,34 @@ +#[cfg(any(unix, target_os = "wasi"))] +#[test] +fn test_raw_fd() { + #[cfg(unix)] + use crate::os::unix::io::{AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; + #[cfg(target_os = "wasi")] + use crate::os::wasi::io::{AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; + + let raw_fd: RawFd = crate::io::stdin().as_raw_fd(); + + let stdin_as_file = unsafe { crate::fs::File::from_raw_fd(raw_fd) }; + assert_eq!(stdin_as_file.as_raw_fd(), raw_fd); + assert_eq!(unsafe { BorrowedFd::borrow_raw(raw_fd).as_raw_fd() }, raw_fd); + assert_eq!(stdin_as_file.into_raw_fd(), 0); +} + +#[cfg(any(unix, target_os = "wasi"))] +#[test] +fn test_fd() { + #[cfg(unix)] + use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; + #[cfg(target_os = "wasi")] + use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; + + let stdin = crate::io::stdin(); + let fd: BorrowedFd<'_> = stdin.as_fd(); + let raw_fd: RawFd = fd.as_raw_fd(); + let owned_fd: OwnedFd = unsafe { OwnedFd::from_raw_fd(raw_fd) }; + + let stdin_as_file = crate::fs::File::from(owned_fd); + + assert_eq!(stdin_as_file.as_fd().as_raw_fd(), raw_fd); + assert_eq!(Into::<OwnedFd>::into(stdin_as_file).into_raw_fd(), raw_fd); +} diff --git a/library/std/src/os/raw/char.md b/library/std/src/os/raw/char.md deleted file mode 100644 index 375d070516e..00000000000 --- a/library/std/src/os/raw/char.md +++ /dev/null @@ -1,9 +0,0 @@ -Equivalent to C's `char` type. - -[C's `char` type] is completely unlike [Rust's `char` type]; while Rust's type represents a unicode scalar value, C's `char` type is just an ordinary integer. On modern architectures this type will always be either [`i8`] or [`u8`], as they use byte-addresses memory with 8-bit bytes. - -C chars are most commonly used to make C strings. Unlike Rust, where the length of a string is included alongside the string, C strings mark the end of a string with the character `'\0'`. See [`CStr`] for more information. - -[C's `char` type]: https://en.wikipedia.org/wiki/C_data_types#Basic_types -[Rust's `char` type]: char -[`CStr`]: crate::ffi::CStr diff --git a/library/std/src/os/raw/double.md b/library/std/src/os/raw/double.md deleted file mode 100644 index 57f4534829e..00000000000 --- a/library/std/src/os/raw/double.md +++ /dev/null @@ -1,6 +0,0 @@ -Equivalent to C's `double` type. - -This type will almost always be [`f64`], which is guaranteed to be an [IEEE-754 double-precision float] in Rust. That said, the standard technically only guarantees that it be a floating-point number with at least the precision of a [`float`], and it may be `f32` or something entirely different from the IEEE-754 standard. - -[IEEE-754 double-precision float]: https://en.wikipedia.org/wiki/IEEE_754 -[`float`]: c_float diff --git a/library/std/src/os/raw/float.md b/library/std/src/os/raw/float.md deleted file mode 100644 index 61e2abc0518..00000000000 --- a/library/std/src/os/raw/float.md +++ /dev/null @@ -1,5 +0,0 @@ -Equivalent to C's `float` type. - -This type will almost always be [`f32`], which is guaranteed to be an [IEEE-754 single-precision float] in Rust. That said, the standard technically only guarantees that it be a floating-point number, and it may have less precision than `f32` or not follow the IEEE-754 standard at all. - -[IEEE-754 single-precision float]: https://en.wikipedia.org/wiki/IEEE_754 diff --git a/library/std/src/os/raw/int.md b/library/std/src/os/raw/int.md deleted file mode 100644 index 8062ff2307a..00000000000 --- a/library/std/src/os/raw/int.md +++ /dev/null @@ -1,5 +0,0 @@ -Equivalent to C's `signed int` (`int`) type. - -This type will almost always be [`i32`], but may differ on some esoteric systems. The C standard technically only requires that this type be a signed integer that is at least the size of a [`short`]; some systems define it as an [`i16`], for example. - -[`short`]: c_short diff --git a/library/std/src/os/raw/long.md b/library/std/src/os/raw/long.md deleted file mode 100644 index cc160783f78..00000000000 --- a/library/std/src/os/raw/long.md +++ /dev/null @@ -1,5 +0,0 @@ -Equivalent to C's `signed long` (`long`) type. - -This type will always be [`i32`] or [`i64`]. Most notably, many Linux-based systems assume an `i64`, but Windows assumes `i32`. The C standard technically only requires that this type be a signed integer that is at least 32 bits and at least the size of an [`int`], although in practice, no system would have a `long` that is neither an `i32` nor `i64`. - -[`int`]: c_int diff --git a/library/std/src/os/raw/longlong.md b/library/std/src/os/raw/longlong.md deleted file mode 100644 index 49c61bd61f4..00000000000 --- a/library/std/src/os/raw/longlong.md +++ /dev/null @@ -1,5 +0,0 @@ -Equivalent to C's `signed long long` (`long long`) type. - -This type will almost always be [`i64`], but may differ on some systems. The C standard technically only requires that this type be a signed integer that is at least 64 bits and at least the size of a [`long`], although in practice, no system would have a `long long` that is not an `i64`, as most systems do not have a standardised [`i128`] type. - -[`long`]: c_int diff --git a/library/std/src/os/raw/mod.rs b/library/std/src/os/raw/mod.rs index b6d5199341c..19d0ffb2e39 100644 --- a/library/std/src/os/raw/mod.rs +++ b/library/std/src/os/raw/mod.rs @@ -1,156 +1,31 @@ -//! Platform-specific types, as defined by C. -//! -//! Code that interacts via FFI will almost certainly be using the -//! base types provided by C, which aren't nearly as nicely defined -//! as Rust's primitive types. This module provides types which will -//! match those defined by C, so that code that interacts with C will -//! refer to the correct types. +//! Compatibility module for C platform-specific types. Use [`core::ffi`] instead. #![stable(feature = "raw_os", since = "1.1.0")] #[cfg(test)] mod tests; -use core::num::*; - -macro_rules! type_alias_no_nz { - { - $Docfile:tt, $Alias:ident = $Real:ty; - $( $Cfg:tt )* - } => { - #[doc = include_str!($Docfile)] - $( $Cfg )* +macro_rules! alias_core_ffi { + ($($t:ident)*) => {$( #[stable(feature = "raw_os", since = "1.1.0")] - pub type $Alias = $Real; - } -} - -// To verify that the NonZero types in this file's macro invocations correspond -// -// perl -n < library/std/src/os/raw/mod.rs -e 'next unless m/type_alias\!/; die "$_ ?" unless m/, (c_\w+) = (\w+), NonZero_(\w+) = NonZero(\w+)/; die "$_ ?" unless $3 eq $1 and $4 eq ucfirst $2' -// -// NB this does not check that the main c_* types are right. - -macro_rules! type_alias { - { - $Docfile:tt, $Alias:ident = $Real:ty, $NZAlias:ident = $NZReal:ty; - $( $Cfg:tt )* - } => { - type_alias_no_nz! { $Docfile, $Alias = $Real; $( $Cfg )* } - - #[doc = concat!("Type alias for `NonZero` version of [`", stringify!($Alias), "`]")] - #[unstable(feature = "raw_os_nonzero", issue = "82363")] - $( $Cfg )* - pub type $NZAlias = $NZReal; - } + #[doc = include_str!(concat!("../../../../core/src/ffi/", stringify!($t), ".md"))] + // Make this type alias appear cfg-dependent so that Clippy does not suggest + // replacing expressions like `0 as c_char` with `0_i8`/`0_u8`. This #[cfg(all())] can be + // removed after the false positive in https://github.com/rust-lang/rust-clippy/issues/8093 + // is fixed. + #[cfg(all())] + #[doc(cfg(all()))] + pub type $t = core::ffi::$t; + )*} } -type_alias! { "char.md", c_char = c_char_definition::c_char, NonZero_c_char = c_char_definition::NonZero_c_char; -// Make this type alias appear cfg-dependent so that Clippy does not suggest -// replacing `0 as c_char` with `0_i8`/`0_u8`. This #[cfg(all())] can be removed -// after the false positive in https://github.com/rust-lang/rust-clippy/issues/8093 -// is fixed. -#[cfg(all())] -#[doc(cfg(all()))] } -type_alias! { "schar.md", c_schar = i8, NonZero_c_schar = NonZeroI8; } -type_alias! { "uchar.md", c_uchar = u8, NonZero_c_uchar = NonZeroU8; } -type_alias! { "short.md", c_short = i16, NonZero_c_short = NonZeroI16; } -type_alias! { "ushort.md", c_ushort = u16, NonZero_c_ushort = NonZeroU16; } -type_alias! { "int.md", c_int = i32, NonZero_c_int = NonZeroI32; } -type_alias! { "uint.md", c_uint = u32, NonZero_c_uint = NonZeroU32; } -type_alias! { "long.md", c_long = i32, NonZero_c_long = NonZeroI32; -#[doc(cfg(all()))] -#[cfg(any(target_pointer_width = "32", windows))] } -type_alias! { "ulong.md", c_ulong = u32, NonZero_c_ulong = NonZeroU32; -#[doc(cfg(all()))] -#[cfg(any(target_pointer_width = "32", windows))] } -type_alias! { "long.md", c_long = i64, NonZero_c_long = NonZeroI64; -#[doc(cfg(all()))] -#[cfg(all(target_pointer_width = "64", not(windows)))] } -type_alias! { "ulong.md", c_ulong = u64, NonZero_c_ulong = NonZeroU64; -#[doc(cfg(all()))] -#[cfg(all(target_pointer_width = "64", not(windows)))] } -type_alias! { "longlong.md", c_longlong = i64, NonZero_c_longlong = NonZeroI64; } -type_alias! { "ulonglong.md", c_ulonglong = u64, NonZero_c_ulonglong = NonZeroU64; } -type_alias_no_nz! { "float.md", c_float = f32; } -type_alias_no_nz! { "double.md", c_double = f64; } - -#[stable(feature = "raw_os", since = "1.1.0")] -#[doc(no_inline)] -pub use core::ffi::c_void; - -/// Equivalent to C's `size_t` type, from `stddef.h` (or `cstddef` for C++). -/// -/// This type is currently always [`usize`], however in the future there may be -/// platforms where this is not the case. -#[unstable(feature = "c_size_t", issue = "88345")] -pub type c_size_t = usize; - -/// Equivalent to C's `ptrdiff_t` type, from `stddef.h` (or `cstddef` for C++). -/// -/// This type is currently always [`isize`], however in the future there may be -/// platforms where this is not the case. -#[unstable(feature = "c_size_t", issue = "88345")] -pub type c_ptrdiff_t = isize; - -/// Equivalent to C's `ssize_t` (on POSIX) or `SSIZE_T` (on Windows) type. -/// -/// This type is currently always [`isize`], however in the future there may be -/// platforms where this is not the case. -#[unstable(feature = "c_size_t", issue = "88345")] -pub type c_ssize_t = isize; - -mod c_char_definition { - cfg_if::cfg_if! { - // These are the targets on which c_char is unsigned. - if #[cfg(any( - all( - target_os = "linux", - any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "hexagon", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "s390x", - target_arch = "riscv64", - target_arch = "riscv32" - ) - ), - all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")), - all(target_os = "l4re", target_arch = "x86_64"), - all( - target_os = "freebsd", - any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "riscv64" - ) - ), - all( - target_os = "netbsd", - any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc") - ), - all(target_os = "openbsd", target_arch = "aarch64"), - all( - target_os = "vxworks", - any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc64", - target_arch = "powerpc" - ) - ), - all(target_os = "fuchsia", target_arch = "aarch64") - ))] { - pub type c_char = u8; - pub type NonZero_c_char = core::num::NonZeroU8; - } else { - // On every other target, c_char is signed. - pub type c_char = i8; - pub type NonZero_c_char = core::num::NonZeroI8; - } - } +alias_core_ffi! { + c_char c_schar c_uchar + c_short c_ushort + c_int c_uint + c_long c_ulong + c_longlong c_ulonglong + c_float + c_double + c_void } diff --git a/library/std/src/os/raw/schar.md b/library/std/src/os/raw/schar.md deleted file mode 100644 index 69879c9f17f..00000000000 --- a/library/std/src/os/raw/schar.md +++ /dev/null @@ -1,5 +0,0 @@ -Equivalent to C's `signed char` type. - -This type will always be [`i8`], but is included for completeness. It is defined as being a signed integer the same size as a C [`char`]. - -[`char`]: c_char diff --git a/library/std/src/os/raw/short.md b/library/std/src/os/raw/short.md deleted file mode 100644 index 3d1e53d1325..00000000000 --- a/library/std/src/os/raw/short.md +++ /dev/null @@ -1,5 +0,0 @@ -Equivalent to C's `signed short` (`short`) type. - -This type will almost always be [`i16`], but may differ on some esoteric systems. The C standard technically only requires that this type be a signed integer with at least 16 bits; some systems may define it as `i32`, for example. - -[`char`]: c_char diff --git a/library/std/src/os/raw/uchar.md b/library/std/src/os/raw/uchar.md deleted file mode 100644 index b633bb7f8da..00000000000 --- a/library/std/src/os/raw/uchar.md +++ /dev/null @@ -1,5 +0,0 @@ -Equivalent to C's `unsigned char` type. - -This type will always be [`u8`], but is included for completeness. It is defined as being an unsigned integer the same size as a C [`char`]. - -[`char`]: c_char diff --git a/library/std/src/os/raw/uint.md b/library/std/src/os/raw/uint.md deleted file mode 100644 index f3abea35937..00000000000 --- a/library/std/src/os/raw/uint.md +++ /dev/null @@ -1,5 +0,0 @@ -Equivalent to C's `unsigned int` type. - -This type will almost always be [`u32`], but may differ on some esoteric systems. The C standard technically only requires that this type be an unsigned integer with the same size as an [`int`]; some systems define it as a [`u16`], for example. - -[`int`]: c_int diff --git a/library/std/src/os/raw/ulong.md b/library/std/src/os/raw/ulong.md deleted file mode 100644 index 4ab304e6577..00000000000 --- a/library/std/src/os/raw/ulong.md +++ /dev/null @@ -1,5 +0,0 @@ -Equivalent to C's `unsigned long` type. - -This type will always be [`u32`] or [`u64`]. Most notably, many Linux-based systems assume an `u64`, but Windows assumes `u32`. The C standard technically only requires that this type be an unsigned integer with the size of a [`long`], although in practice, no system would have a `ulong` that is neither a `u32` nor `u64`. - -[`long`]: c_long diff --git a/library/std/src/os/raw/ulonglong.md b/library/std/src/os/raw/ulonglong.md deleted file mode 100644 index a27d70e1753..00000000000 --- a/library/std/src/os/raw/ulonglong.md +++ /dev/null @@ -1,5 +0,0 @@ -Equivalent to C's `unsigned long long` type. - -This type will almost always be [`u64`], but may differ on some systems. The C standard technically only requires that this type be an unsigned integer with the size of a [`long long`], although in practice, no system would have a `long long` that is not a `u64`, as most systems do not have a standardised [`u128`] type. - -[`long long`]: c_longlong diff --git a/library/std/src/os/raw/ushort.md b/library/std/src/os/raw/ushort.md deleted file mode 100644 index 6928e51b352..00000000000 --- a/library/std/src/os/raw/ushort.md +++ /dev/null @@ -1,5 +0,0 @@ -Equivalent to C's `unsigned short` type. - -This type will almost always be [`u16`], but may differ on some esoteric systems. The C standard technically only requires that this type be an unsigned integer with the same size as a [`short`]. - -[`short`]: c_short diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs index 75d65e6d5fc..3fc6cc44ce4 100644 --- a/library/std/src/os/unix/fs.rs +++ b/library/std/src/os/unix/fs.rs @@ -47,7 +47,7 @@ pub trait FileExt { /// /// // We now read 8 bytes from the offset 10. /// let num_bytes_read = file.read_at(&mut buf, 10)?; - /// println!("read {} bytes: {:?}", num_bytes_read, buf); + /// println!("read {num_bytes_read} bytes: {buf:?}"); /// Ok(()) /// } /// ``` @@ -861,7 +861,7 @@ pub trait DirEntryExt2: Sealed { /// entries.sort_unstable_by(|a, b| a.file_name_ref().cmp(b.file_name_ref())); /// /// for p in entries { - /// println!("{:?}", p); + /// println!("{p:?}"); /// } /// /// Ok(()) diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index 034fa301ba1..a3ef4b2d92c 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -86,7 +86,7 @@ impl<'a> fmt::Display for AsciiEscaped<'a> { /// let socket = match UnixListener::bind("/tmp/sock") { /// Ok(sock) => sock, /// Err(e) => { -/// println!("Couldn't bind: {:?}", e); +/// println!("Couldn't bind: {e:?}"); /// return /// } /// }; @@ -140,12 +140,11 @@ impl SocketAddr { /// # Examples /// /// ``` - /// #![feature(unix_socket_creation)] /// use std::os::unix::net::SocketAddr; /// use std::path::Path; /// /// # fn main() -> std::io::Result<()> { - /// let address = SocketAddr::from_path("/path/to/socket")?; + /// let address = SocketAddr::from_pathname("/path/to/socket")?; /// assert_eq!(address.as_pathname(), Some(Path::new("/path/to/socket"))); /// # Ok(()) /// # } @@ -154,13 +153,12 @@ impl SocketAddr { /// Creating a `SocketAddr` with a NULL byte results in an error. /// /// ``` - /// #![feature(unix_socket_creation)] /// use std::os::unix::net::SocketAddr; /// - /// assert!(SocketAddr::from_path("/path/with/\0/bytes").is_err()); + /// assert!(SocketAddr::from_pathname("/path/with/\0/bytes").is_err()); /// ``` - #[unstable(feature = "unix_socket_creation", issue = "93423")] - pub fn from_path<P>(path: P) -> io::Result<SocketAddr> + #[stable(feature = "unix_socket_creation", since = "1.61.0")] + pub fn from_pathname<P>(path: P) -> io::Result<SocketAddr> where P: AsRef<Path>, { @@ -307,7 +305,7 @@ impl SocketAddr { /// let listener = match UnixListener::bind_addr(&addr) { /// Ok(sock) => sock, /// Err(err) => { - /// println!("Couldn't bind: {:?}", err); + /// println!("Couldn't bind: {err:?}"); /// return Err(err); /// } /// }; @@ -346,7 +344,7 @@ impl fmt::Debug for SocketAddr { match self.address() { AddressKind::Unnamed => write!(fmt, "(unnamed)"), AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)), - AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path), + AddressKind::Pathname(path) => write!(fmt, "{path:?} (pathname)"), } } } diff --git a/library/std/src/os/unix/net/ancillary.rs b/library/std/src/os/unix/net/ancillary.rs index 6e6f5212b46..fb1ff4b725c 100644 --- a/library/std/src/os/unix/net/ancillary.rs +++ b/library/std/src/os/unix/net/ancillary.rs @@ -396,7 +396,7 @@ impl<'a> Iterator for Messages<'a> { /// for ancillary_result in ancillary.messages() { /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() { /// for fd in scm_rights { -/// println!("receive file descriptor: {}", fd); +/// println!("receive file descriptor: {fd}"); /// } /// } /// } @@ -568,7 +568,7 @@ impl<'a> SocketAncillary<'a> { /// for ancillary_result in ancillary.messages() { /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() { /// for fd in scm_rights { - /// println!("receive file descriptor: {}", fd); + /// println!("receive file descriptor: {fd}"); /// } /// } /// } @@ -579,7 +579,7 @@ impl<'a> SocketAncillary<'a> { /// for ancillary_result in ancillary.messages() { /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() { /// for fd in scm_rights { - /// println!("receive file descriptor: {}", fd); + /// println!("receive file descriptor: {fd}"); /// } /// } /// } diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs index a2caccc7849..59c91e9a82e 100644 --- a/library/std/src/os/unix/net/datagram.rs +++ b/library/std/src/os/unix/net/datagram.rs @@ -95,7 +95,7 @@ impl UnixDatagram { /// let sock = match UnixDatagram::bind("/path/to/the/socket") { /// Ok(sock) => sock, /// Err(e) => { - /// println!("Couldn't bind: {:?}", e); + /// println!("Couldn't bind: {e:?}"); /// return /// } /// }; @@ -127,7 +127,7 @@ impl UnixDatagram { /// let sock2 = match UnixDatagram::bind_addr(&addr) { /// Ok(sock) => sock, /// Err(err) => { - /// println!("Couldn't bind: {:?}", err); + /// println!("Couldn't bind: {err:?}"); /// return Err(err); /// } /// }; @@ -157,7 +157,7 @@ impl UnixDatagram { /// let sock = match UnixDatagram::unbound() { /// Ok(sock) => sock, /// Err(e) => { - /// println!("Couldn't unbound: {:?}", e); + /// println!("Couldn't unbound: {e:?}"); /// return /// } /// }; @@ -180,7 +180,7 @@ impl UnixDatagram { /// let (sock1, sock2) = match UnixDatagram::pair() { /// Ok((sock1, sock2)) => (sock1, sock2), /// Err(e) => { - /// println!("Couldn't unbound: {:?}", e); + /// println!("Couldn't unbound: {e:?}"); /// return /// } /// }; @@ -210,7 +210,7 @@ impl UnixDatagram { /// match sock.connect("/path/to/the/socket") { /// Ok(sock) => sock, /// Err(e) => { - /// println!("Couldn't connect: {:?}", e); + /// println!("Couldn't connect: {e:?}"); /// return Err(e) /// } /// }; @@ -243,7 +243,7 @@ impl UnixDatagram { /// match sock.connect_addr(&addr) { /// Ok(sock) => sock, /// Err(e) => { - /// println!("Couldn't connect: {:?}", e); + /// println!("Couldn't connect: {e:?}"); /// return Err(e) /// } /// }; @@ -367,7 +367,7 @@ impl UnixDatagram { /// let sock = UnixDatagram::unbound()?; /// let mut buf = vec![0; 10]; /// let (size, sender) = sock.recv_from(buf.as_mut_slice())?; - /// println!("received {} bytes from {:?}", size, sender); + /// println!("received {size} bytes from {sender:?}"); /// Ok(()) /// } /// ``` @@ -422,11 +422,11 @@ impl UnixDatagram { /// let mut ancillary_buffer = [0; 128]; /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); /// let (size, _truncated, sender) = sock.recv_vectored_with_ancillary_from(bufs, &mut ancillary)?; - /// println!("received {}", size); + /// println!("received {size}"); /// for ancillary_result in ancillary.messages() { /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() { /// for fd in scm_rights { - /// println!("receive file descriptor: {}", fd); + /// println!("receive file descriptor: {fd}"); /// } /// } /// } @@ -479,11 +479,11 @@ impl UnixDatagram { /// let mut ancillary_buffer = [0; 128]; /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); /// let (size, _truncated) = sock.recv_vectored_with_ancillary(bufs, &mut ancillary)?; - /// println!("received {}", size); + /// println!("received {size}"); /// for ancillary_result in ancillary.messages() { /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() { /// for fd in scm_rights { - /// println!("receive file descriptor: {}", fd); + /// println!("receive file descriptor: {fd}"); /// } /// } /// } @@ -893,7 +893,7 @@ impl UnixDatagram { /// fn main() -> std::io::Result<()> { /// let sock = UnixDatagram::unbound()?; /// if let Ok(Some(err)) = sock.take_error() { - /// println!("Got error: {:?}", err); + /// println!("Got error: {err:?}"); /// } /// Ok(()) /// } diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index b23dd6062f6..8e11d32f130 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -63,7 +63,7 @@ impl UnixListener { /// let listener = match UnixListener::bind("/path/to/the/socket") { /// Ok(sock) => sock, /// Err(e) => { - /// println!("Couldn't connect: {:?}", e); + /// println!("Couldn't connect: {e:?}"); /// return /// } /// }; @@ -98,7 +98,7 @@ impl UnixListener { /// let listener2 = match UnixListener::bind_addr(&addr) { /// Ok(sock) => sock, /// Err(err) => { - /// println!("Couldn't bind: {:?}", err); + /// println!("Couldn't bind: {err:?}"); /// return Err(err); /// } /// }; @@ -136,8 +136,8 @@ impl UnixListener { /// let listener = UnixListener::bind("/path/to/the/socket")?; /// /// match listener.accept() { - /// Ok((socket, addr)) => println!("Got a client: {:?}", addr), - /// Err(e) => println!("accept function failed: {:?}", e), + /// Ok((socket, addr)) => println!("Got a client: {addr:?}"), + /// Err(e) => println!("accept function failed: {e:?}"), /// } /// Ok(()) /// } @@ -226,7 +226,7 @@ impl UnixListener { /// let listener = UnixListener::bind("/tmp/sock")?; /// /// if let Ok(Some(err)) = listener.take_error() { - /// println!("Got error: {:?}", err); + /// println!("Got error: {err:?}"); /// } /// Ok(()) /// } diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index 583f861a925..3943b4fed09 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -57,7 +57,7 @@ pub use ucred::UCred; /// stream.write_all(b"hello world")?; /// let mut response = String::new(); /// stream.read_to_string(&mut response)?; -/// println!("{}", response); +/// println!("{response}"); /// Ok(()) /// } /// ``` @@ -90,7 +90,7 @@ impl UnixStream { /// let socket = match UnixStream::connect("/tmp/sock") { /// Ok(sock) => sock, /// Err(e) => { - /// println!("Couldn't connect: {:?}", e); + /// println!("Couldn't connect: {e:?}"); /// return /// } /// }; @@ -123,7 +123,7 @@ impl UnixStream { /// let sock = match UnixStream::connect_addr(&addr) { /// Ok(sock) => sock, /// Err(e) => { - /// println!("Couldn't connect: {:?}", e); + /// println!("Couldn't connect: {e:?}"); /// return Err(e) /// } /// }; @@ -155,7 +155,7 @@ impl UnixStream { /// let (sock1, sock2) = match UnixStream::pair() { /// Ok((sock1, sock2)) => (sock1, sock2), /// Err(e) => { - /// println!("Couldn't create a pair of sockets: {:?}", e); + /// println!("Couldn't create a pair of sockets: {e:?}"); /// return /// } /// }; @@ -443,7 +443,7 @@ impl UnixStream { /// fn main() -> std::io::Result<()> { /// let socket = UnixStream::connect("/tmp/sock")?; /// if let Ok(Some(err)) = socket.take_error() { - /// println!("Got error: {:?}", err); + /// println!("Got error: {err:?}"); /// } /// Ok(()) /// } @@ -530,11 +530,11 @@ impl UnixStream { /// let mut ancillary_buffer = [0; 128]; /// let mut ancillary = SocketAncillary::new(&mut ancillary_buffer[..]); /// let size = socket.recv_vectored_with_ancillary(bufs, &mut ancillary)?; - /// println!("received {}", size); + /// println!("received {size}"); /// for ancillary_result in ancillary.messages() { /// if let AncillaryData::ScmRights(scm_rights) = ancillary_result.unwrap() { /// for fd in scm_rights { - /// println!("receive file descriptor: {}", fd); + /// println!("receive file descriptor: {fd}"); /// } /// } /// } diff --git a/library/std/src/os/unix/net/tests.rs b/library/std/src/os/unix/net/tests.rs index 7ad4a02611e..aa0df61c192 100644 --- a/library/std/src/os/unix/net/tests.rs +++ b/library/std/src/os/unix/net/tests.rs @@ -29,7 +29,7 @@ macro_rules! or_panic { ($e:expr) => { match $e { Ok(e) => e, - Err(e) => panic!("{}", e), + Err(e) => panic!("{e}"), } }; } @@ -161,19 +161,19 @@ fn long_path() { ); match UnixStream::connect(&socket_path) { Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} - Err(e) => panic!("unexpected error {}", e), + Err(e) => panic!("unexpected error {e}"), Ok(_) => panic!("unexpected success"), } match UnixListener::bind(&socket_path) { Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} - Err(e) => panic!("unexpected error {}", e), + Err(e) => panic!("unexpected error {e}"), Ok(_) => panic!("unexpected success"), } match UnixDatagram::bind(&socket_path) { Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} - Err(e) => panic!("unexpected error {}", e), + Err(e) => panic!("unexpected error {e}"), Ok(_) => panic!("unexpected success"), } } @@ -524,7 +524,7 @@ fn test_abstract_namespace_too_long() { jklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", ) { Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} - Err(e) => panic!("unexpected error {}", e), + Err(e) => panic!("unexpected error {e}"), Ok(_) => panic!("unexpected success"), } } @@ -564,7 +564,7 @@ fn test_unix_stream_peek() { match stream.peek(&mut buf) { Ok(_) => panic!("expected error"), Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} - Err(e) => panic!("unexpected error: {}", e), + Err(e) => panic!("unexpected error: {e}"), } or_panic!(txdone.send(())); diff --git a/library/std/src/os/windows/fs.rs b/library/std/src/os/windows/fs.rs index 31d1e3c1e42..f15baff59db 100644 --- a/library/std/src/os/windows/fs.rs +++ b/library/std/src/os/windows/fs.rs @@ -158,6 +158,7 @@ pub trait OpenOptionsExt { /// # Examples /// /// ```no_run + /// # #![allow(unexpected_cfgs)] /// # #[cfg(for_demonstration_only)] /// extern crate winapi; /// # mod winapi { pub const FILE_FLAG_DELETE_ON_CLOSE: u32 = 0x04000000; } @@ -195,6 +196,7 @@ pub trait OpenOptionsExt { /// # Examples /// /// ```no_run + /// # #![allow(unexpected_cfgs)] /// # #[cfg(for_demonstration_only)] /// extern crate winapi; /// # mod winapi { pub const FILE_ATTRIBUTE_HIDDEN: u32 = 2; } @@ -236,6 +238,7 @@ pub trait OpenOptionsExt { /// # Examples /// /// ```no_run + /// # #![allow(unexpected_cfgs)] /// # #[cfg(for_demonstration_only)] /// extern crate winapi; /// # mod winapi { pub const SECURITY_IDENTIFICATION: u32 = 0; } diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index 8df6c54a414..14b94d8dcdf 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -28,6 +28,10 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; /// And, it *may* have the value `NULL` (0), which can occur when consoles are /// detached from processes, or when `windows_subsystem` is used. /// +/// This type's `.to_owned()` implementation returns another `BorrowedHandle` +/// rather than an `OwnedHandle`. It just makes a trivial copy of the raw +/// handle, which is then borrowed under the same lifetime. +/// /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 #[derive(Copy, Clone)] #[repr(transparent)] @@ -55,6 +59,7 @@ pub struct BorrowedHandle<'handle> { /// [`RegCloseKey`]: https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regclosekey /// /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 +#[repr(transparent)] #[unstable(feature = "io_safety", issue = "87074")] pub struct OwnedHandle { handle: RawHandle, @@ -131,7 +136,7 @@ impl BorrowedHandle<'_> { /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 #[inline] #[unstable(feature = "io_safety", issue = "87074")] - pub unsafe fn borrow_raw_handle(handle: RawHandle) -> Self { + pub unsafe fn borrow_raw(handle: RawHandle) -> Self { Self { handle, _phantom: PhantomData } } } @@ -210,29 +215,13 @@ impl IntoRawHandle for OwnedHandle { } impl FromRawHandle for OwnedHandle { - /// Constructs a new instance of `Self` from the given raw handle. - /// - /// # Safety - /// - /// The resource pointed to by `handle` must be open and suitable for - /// assuming ownership. The resource must not require any cleanup other - /// than `CloseHandle`. - /// - /// In particular, it must not be used with handles to open registry - /// keys which need to be closed with [`RegCloseKey`] instead. - /// - /// Note that it *may* have the value `INVALID_HANDLE_VALUE` (-1), which is - /// sometimes a valid handle value. See [here] for the full story. - /// - /// [`RegCloseKey`]: https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regclosekey - /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 #[inline] unsafe fn from_raw_handle(handle: RawHandle) -> Self { Self { handle } } } -impl FromRawHandle for HandleOrNull { +impl HandleOrNull { /// Constructs a new instance of `Self` from the given `RawHandle` returned /// from a Windows API that uses null to indicate failure, such as /// `CreateThread`. @@ -242,18 +231,18 @@ impl FromRawHandle for HandleOrNull { /// /// # Safety /// - /// The resource pointed to by `handle` must be either open and otherwise - /// unowned, or null. Note that not all Windows APIs use null for errors; - /// see [here] for the full story. + /// The passed `handle` value must either satisfy the safety requirements + /// of [`FromRawHandle::from_raw_handle`], or be null. Note that not all + /// Windows APIs use null for errors; see [here] for the full story. /// /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 #[inline] - unsafe fn from_raw_handle(handle: RawHandle) -> Self { + pub unsafe fn from_raw_handle(handle: RawHandle) -> Self { Self(OwnedHandle::from_raw_handle(handle)) } } -impl FromRawHandle for HandleOrInvalid { +impl HandleOrInvalid { /// Constructs a new instance of `Self` from the given `RawHandle` returned /// from a Windows API that uses `INVALID_HANDLE_VALUE` to indicate /// failure, such as `CreateFileW`. @@ -263,14 +252,14 @@ impl FromRawHandle for HandleOrInvalid { /// /// # Safety /// - /// The resource pointed to by `handle` must be either open and otherwise - /// unowned, null, or equal to `INVALID_HANDLE_VALUE` (-1). Note that not - /// all Windows APIs use `INVALID_HANDLE_VALUE` for errors; see [here] for - /// the full story. + /// The passed `handle` value must either satisfy the safety requirements + /// of [`FromRawHandle::from_raw_handle`], or be + /// `INVALID_HANDLE_VALUE` (-1). Note that not all Windows APIs use + /// `INVALID_HANDLE_VALUE` for errors; see [here] for the full story. /// /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 #[inline] - unsafe fn from_raw_handle(handle: RawHandle) -> Self { + pub unsafe fn from_raw_handle(handle: RawHandle) -> Self { Self(OwnedHandle::from_raw_handle(handle)) } } @@ -345,7 +334,7 @@ impl AsHandle for OwnedHandle { // Safety: `OwnedHandle` and `BorrowedHandle` have the same validity // invariants, and the `BorrowdHandle` is bounded by the lifetime // of `&self`. - unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } @@ -373,49 +362,49 @@ impl From<OwnedHandle> for fs::File { impl AsHandle for crate::io::Stdin { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } impl<'a> AsHandle for crate::io::StdinLock<'a> { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } impl AsHandle for crate::io::Stdout { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } impl<'a> AsHandle for crate::io::StdoutLock<'a> { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } impl AsHandle for crate::io::Stderr { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } impl<'a> AsHandle for crate::io::StderrLock<'a> { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } impl AsHandle for crate::process::ChildStdin { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } @@ -429,7 +418,7 @@ impl From<crate::process::ChildStdin> for OwnedHandle { impl AsHandle for crate::process::ChildStdout { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } @@ -443,7 +432,7 @@ impl From<crate::process::ChildStdout> for OwnedHandle { impl AsHandle for crate::process::ChildStderr { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } @@ -457,7 +446,7 @@ impl From<crate::process::ChildStderr> for OwnedHandle { impl<T> AsHandle for crate::thread::JoinHandle<T> { #[inline] fn as_handle(&self) -> BorrowedHandle<'_> { - unsafe { BorrowedHandle::borrow_raw_handle(self.as_raw_handle()) } + unsafe { BorrowedHandle::borrow_raw(self.as_raw_handle()) } } } diff --git a/library/std/src/os/windows/io/raw.rs b/library/std/src/os/windows/io/raw.rs index c7f122048a1..48c5fd358d9 100644 --- a/library/std/src/os/windows/io/raw.rs +++ b/library/std/src/os/windows/io/raw.rs @@ -5,6 +5,8 @@ use crate::fs; use crate::io; use crate::net; +#[cfg(doc)] +use crate::os::windows::io::{AsHandle, AsSocket}; use crate::os::windows::io::{OwnedHandle, OwnedSocket}; use crate::os::windows::raw; use crate::sys; @@ -22,7 +24,15 @@ pub type RawSocket = raw::SOCKET; /// Extracts raw handles. #[stable(feature = "rust1", since = "1.0.0")] pub trait AsRawHandle { - /// Extracts the raw handle, without taking any ownership. + /// Extracts the raw handle. + /// + /// This function is typically used to **borrow** an owned handle. + /// When used in this way, this method does **not** pass ownership of the + /// raw handle to the caller, and the handle is only guaranteed + /// to be valid while the original object has not yet been destroyed. + /// + /// However, borrowing is not strictly required. See [`AsHandle::as_handle`] + /// for an API which strictly borrows a handle. #[stable(feature = "rust1", since = "1.0.0")] fn as_raw_handle(&self) -> RawHandle; } @@ -32,15 +42,28 @@ pub trait AsRawHandle { pub trait FromRawHandle { /// Constructs a new I/O object from the specified raw handle. /// - /// This function will **consume ownership** of the handle given, - /// passing responsibility for closing the handle to the returned - /// object. + /// This function is typically used to **consume ownership** of the handle + /// given, passing responsibility for closing the handle to the returned + /// object. When used in this way, the returned object + /// will take responsibility for closing it when the object goes out of + /// scope. + /// + /// However, consuming ownership is not strictly required. Use a + /// `From<OwnedHandle>::from` implementation for an API which strictly + /// consumes ownership. + /// + /// # Safety /// - /// This function is also unsafe as the primitives currently returned - /// have the contract that they are the sole owner of the file - /// descriptor they are wrapping. Usage of this function could - /// accidentally allow violating this contract which can cause memory - /// unsafety in code that relies on it being true. + /// The `handle` passed in must: + /// - be a valid an open handle, + /// - be a handle for a resource that may be freed via [`CloseHandle`] + /// (as opposed to `RegCloseKey` or other close functions). + /// + /// Note that the handle *may* have the value `INVALID_HANDLE_VALUE` (-1), + /// which is sometimes a valid handle value. See [here] for the full story. + /// + /// [`CloseHandle`]: https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle + /// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443 #[stable(feature = "from_raw_os", since = "1.1.0")] unsafe fn from_raw_handle(handle: RawHandle) -> Self; } @@ -51,9 +74,13 @@ pub trait FromRawHandle { pub trait IntoRawHandle { /// Consumes this object, returning the raw underlying handle. /// - /// This function **transfers ownership** of the underlying handle to the - /// caller. Callers are then the unique owners of the handle and must close - /// it once it's no longer needed. + /// This function is typically used to **transfer ownership** of the underlying + /// handle to the caller. When used in this way, callers are then the unique + /// owners of the handle and must close it once it's no longer needed. + /// + /// However, transferring ownership is not strictly required. Use a + /// `Into<OwnedHandle>::into` implementation for an API which strictly + /// transfers ownership. #[stable(feature = "into_raw_os", since = "1.4.0")] fn into_raw_handle(self) -> RawHandle; } @@ -130,7 +157,15 @@ impl IntoRawHandle for fs::File { /// Extracts raw sockets. #[stable(feature = "rust1", since = "1.0.0")] pub trait AsRawSocket { - /// Extracts the underlying raw socket from this object. + /// Extracts the raw socket. + /// + /// This function is typically used to **borrow** an owned socket. + /// When used in this way, this method does **not** pass ownership of the + /// raw socket to the caller, and the socket is only guaranteed + /// to be valid while the original object has not yet been destroyed. + /// + /// However, borrowing is not strictly required. See [`AsSocket::as_socket`] + /// for an API which strictly borrows a socket. #[stable(feature = "rust1", since = "1.0.0")] fn as_raw_socket(&self) -> RawSocket; } @@ -138,16 +173,25 @@ pub trait AsRawSocket { /// Creates I/O objects from raw sockets. #[stable(feature = "from_raw_os", since = "1.1.0")] pub trait FromRawSocket { - /// Creates a new I/O object from the given raw socket. + /// Constructs a new I/O object from the specified raw socket. + /// + /// This function is typically used to **consume ownership** of the socket + /// given, passing responsibility for closing the socket to the returned + /// object. When used in this way, the returned object + /// will take responsibility for closing it when the object goes out of + /// scope. /// - /// This function will **consume ownership** of the socket provided and - /// it will be closed when the returned object goes out of scope. + /// However, consuming ownership is not strictly required. Use a + /// `From<OwnedSocket>::from` implementation for an API which strictly + /// consumes ownership. /// - /// This function is also unsafe as the primitives currently returned - /// have the contract that they are the sole owner of the file - /// descriptor they are wrapping. Usage of this function could - /// accidentally allow violating this contract which can cause memory - /// unsafety in code that relies on it being true. + /// # Safety + /// + /// The `socket` passed in must: + /// - be a valid an open socket, + /// - be a socket that may be freed via [`closesocket`]. + /// + /// [`closesocket`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-closesocket #[stable(feature = "from_raw_os", since = "1.1.0")] unsafe fn from_raw_socket(sock: RawSocket) -> Self; } @@ -158,9 +202,13 @@ pub trait FromRawSocket { pub trait IntoRawSocket { /// Consumes this object, returning the raw underlying socket. /// - /// This function **transfers ownership** of the underlying socket to the - /// caller. Callers are then the unique owners of the socket and must close - /// it once it's no longer needed. + /// This function is typically used to **transfer ownership** of the underlying + /// socket to the caller. When used in this way, callers are then the unique + /// owners of the socket and must close it once it's no longer needed. + /// + /// However, transferring ownership is not strictly required. Use a + /// `Into<OwnedSocket>::into` implementation for an API which strictly + /// transfers ownership. #[stable(feature = "into_raw_os", since = "1.4.0")] fn into_raw_socket(self) -> RawSocket; } diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index 2f13eb77a1b..a6b979cc22b 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -21,6 +21,10 @@ use crate::sys::cvt; /// so it can be used in FFI in places where a socket is passed as an argument, /// it is not captured or consumed, and it never has the value /// `INVALID_SOCKET`. +/// +/// This type's `.to_owned()` implementation returns another `BorrowedSocket` +/// rather than an `OwnedSocket`. It just makes a trivial copy of the raw +/// socket, which is then borrowed under the same lifetime. #[derive(Copy, Clone)] #[repr(transparent)] #[rustc_layout_scalar_valid_range_start(0)] @@ -67,7 +71,7 @@ impl BorrowedSocket<'_> { /// `INVALID_SOCKET`. #[inline] #[unstable(feature = "io_safety", issue = "87074")] - pub unsafe fn borrow_raw_socket(socket: RawSocket) -> Self { + pub unsafe fn borrow_raw(socket: RawSocket) -> Self { debug_assert_ne!(socket, c::INVALID_SOCKET as RawSocket); Self { socket, _phantom: PhantomData } } @@ -168,13 +172,6 @@ impl IntoRawSocket for OwnedSocket { } impl FromRawSocket for OwnedSocket { - /// Constructs a new instance of `Self` from the given raw socket. - /// - /// # Safety - /// - /// The resource pointed to by `socket` must be open and suitable for - /// assuming ownership. The resource must not require cleanup other than - /// `closesocket`. #[inline] unsafe fn from_raw_socket(socket: RawSocket) -> Self { debug_assert_ne!(socket, c::INVALID_SOCKET as RawSocket); @@ -239,14 +236,14 @@ impl AsSocket for OwnedSocket { // Safety: `OwnedSocket` and `BorrowedSocket` have the same validity // invariants, and the `BorrowdSocket` is bounded by the lifetime // of `&self`. - unsafe { BorrowedSocket::borrow_raw_socket(self.as_raw_socket()) } + unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) } } } impl AsSocket for crate::net::TcpStream { #[inline] fn as_socket(&self) -> BorrowedSocket<'_> { - unsafe { BorrowedSocket::borrow_raw_socket(self.as_raw_socket()) } + unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) } } } @@ -267,7 +264,7 @@ impl From<OwnedSocket> for crate::net::TcpStream { impl AsSocket for crate::net::TcpListener { #[inline] fn as_socket(&self) -> BorrowedSocket<'_> { - unsafe { BorrowedSocket::borrow_raw_socket(self.as_raw_socket()) } + unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) } } } @@ -288,7 +285,7 @@ impl From<OwnedSocket> for crate::net::TcpListener { impl AsSocket for crate::net::UdpSocket { #[inline] fn as_socket(&self) -> BorrowedSocket<'_> { - unsafe { BorrowedSocket::borrow_raw_socket(self.as_raw_socket()) } + unsafe { BorrowedSocket::borrow_raw(self.as_raw_socket()) } } } diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 2b9ae3210de..03de7eed6d4 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -283,7 +283,7 @@ fn default_hook(info: &PanicInfo<'_>) { let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>"); let write = |err: &mut dyn crate::io::Write| { - let _ = writeln!(err, "thread '{}' panicked at '{}', {}", name, msg, location); + let _ = writeln!(err, "thread '{name}' panicked at '{msg}', {location}"); static FIRST_PANIC: AtomicBool = AtomicBool::new(true); @@ -677,7 +677,7 @@ fn rust_panic_with_hook( // Unfortunately, this does not print a backtrace, because creating // a `Backtrace` will allocate, which we must to avoid here. let panicinfo = PanicInfo::internal_constructor(message, location, can_unwind); - rtprintpanic!("{}\npanicked after panic::always_abort(), aborting.\n", panicinfo); + rtprintpanic!("{panicinfo}\npanicked after panic::always_abort(), aborting.\n"); } crate::sys::abort_internal(); } @@ -745,5 +745,5 @@ fn rust_panic(mut msg: &mut dyn BoxMeUp) -> ! { let obj = &mut msg as *mut &mut dyn BoxMeUp; __rust_start_panic(obj) }; - rtabort!("failed to initiate panic, error {}", code) + rtabort!("failed to initiate panic, error {code}") } diff --git a/library/std/src/path.rs b/library/std/src/path.rs index adb8b30ec08..bcf5c9328b7 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -268,6 +268,12 @@ pub fn is_separator(c: char) -> bool { #[stable(feature = "rust1", since = "1.0.0")] pub const MAIN_SEPARATOR: char = crate::sys::path::MAIN_SEP; +/// The primary separator of path components for the current platform. +/// +/// For example, `/` on Unix and `\` on Windows. +#[unstable(feature = "main_separator_str", issue = "94071")] +pub const MAIN_SEPARATOR_STR: &str = crate::sys::path::MAIN_SEP_STR; + //////////////////////////////////////////////////////////////////////////////// // Misc helpers //////////////////////////////////////////////////////////////////////////////// @@ -586,7 +592,7 @@ impl AsRef<Path> for Component<'_> { /// let path = Path::new("/tmp/foo/bar.txt"); /// /// for component in path.components() { -/// println!("{:?}", component); +/// println!("{component:?}"); /// } /// ``` /// diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs index 8e51433094a..c8dc768d3fc 100644 --- a/library/std/src/path/tests.rs +++ b/library/std/src/path/tests.rs @@ -1586,17 +1586,17 @@ fn test_components_debug() { let mut components = path.components(); let expected = "Components([RootDir, Normal(\"tmp\")])"; - let actual = format!("{:?}", components); + let actual = format!("{components:?}"); assert_eq!(expected, actual); let _ = components.next().unwrap(); let expected = "Components([Normal(\"tmp\")])"; - let actual = format!("{:?}", components); + let actual = format!("{components:?}"); assert_eq!(expected, actual); let _ = components.next().unwrap(); let expected = "Components([])"; - let actual = format!("{:?}", components); + let actual = format!("{components:?}"); assert_eq!(expected, actual); } @@ -1608,17 +1608,17 @@ fn test_iter_debug() { let mut iter = path.iter(); let expected = "Iter([\"/\", \"tmp\"])"; - let actual = format!("{:?}", iter); + let actual = format!("{iter:?}"); assert_eq!(expected, actual); let _ = iter.next().unwrap(); let expected = "Iter([\"tmp\"])"; - let actual = format!("{:?}", iter); + let actual = format!("{iter:?}"); assert_eq!(expected, actual); let _ = iter.next().unwrap(); let expected = "Iter([])"; - let actual = format!("{:?}", iter); + let actual = format!("{iter:?}"); assert_eq!(expected, actual); } @@ -1710,15 +1710,23 @@ fn test_unix_absolute() { let relative = "a/b"; let mut expected = crate::env::current_dir().unwrap(); expected.push(relative); - assert_eq!(absolute(relative).unwrap(), expected); + assert_eq!(absolute(relative).unwrap().as_os_str(), expected.as_os_str()); // Test how components are collected. - assert_eq!(absolute("/a/b/c").unwrap(), Path::new("/a/b/c")); - assert_eq!(absolute("/a//b/c").unwrap(), Path::new("/a/b/c")); - assert_eq!(absolute("//a/b/c").unwrap(), Path::new("//a/b/c")); - assert_eq!(absolute("///a/b/c").unwrap(), Path::new("/a/b/c")); - assert_eq!(absolute("/a/b/c/").unwrap(), Path::new("/a/b/c/")); - assert_eq!(absolute("/a/./b/../c/.././..").unwrap(), Path::new("/a/b/../c/../..")); + assert_eq!(absolute("/a/b/c").unwrap().as_os_str(), Path::new("/a/b/c").as_os_str()); + assert_eq!(absolute("/a//b/c").unwrap().as_os_str(), Path::new("/a/b/c").as_os_str()); + assert_eq!(absolute("//a/b/c").unwrap().as_os_str(), Path::new("//a/b/c").as_os_str()); + assert_eq!(absolute("///a/b/c").unwrap().as_os_str(), Path::new("/a/b/c").as_os_str()); + assert_eq!(absolute("/a/b/c/").unwrap().as_os_str(), Path::new("/a/b/c/").as_os_str()); + assert_eq!( + absolute("/a/./b/../c/.././..").unwrap().as_os_str(), + Path::new("/a/b/../c/../..").as_os_str() + ); + + // Test leading `.` and `..` components + let curdir = crate::env::current_dir().unwrap(); + assert_eq!(absolute("./a").unwrap().as_os_str(), curdir.join("a").as_os_str()); + assert_eq!(absolute("../a").unwrap().as_os_str(), curdir.join("../a").as_os_str()); // return /pwd/../a } #[test] @@ -1762,7 +1770,7 @@ fn test_windows_absolute() { fn bench_path_cmp_fast_path_buf_sort(b: &mut test::Bencher) { let prefix = "my/home"; let mut paths: Vec<_> = - (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {}.rs", num))).collect(); + (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect(); paths.sort(); @@ -1775,7 +1783,7 @@ fn bench_path_cmp_fast_path_buf_sort(b: &mut test::Bencher) { fn bench_path_cmp_fast_path_long(b: &mut test::Bencher) { let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/"; let paths: Vec<_> = - (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {}.rs", num))).collect(); + (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect(); let mut set = BTreeSet::new(); @@ -1793,7 +1801,7 @@ fn bench_path_cmp_fast_path_long(b: &mut test::Bencher) { fn bench_path_cmp_fast_path_short(b: &mut test::Bencher) { let prefix = "my/home"; let paths: Vec<_> = - (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {}.rs", num))).collect(); + (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect(); let mut set = BTreeSet::new(); @@ -1811,7 +1819,7 @@ fn bench_path_cmp_fast_path_short(b: &mut test::Bencher) { fn bench_path_hashset(b: &mut test::Bencher) { let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/"; let paths: Vec<_> = - (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {}.rs", num))).collect(); + (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect(); let mut set = HashSet::new(); @@ -1829,7 +1837,7 @@ fn bench_path_hashset(b: &mut test::Bencher) { fn bench_path_hashset_miss(b: &mut test::Bencher) { let prefix = "/my/home/is/my/castle/and/my/castle/has/a/rusty/workbench/"; let paths: Vec<_> = - (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {}.rs", num))).collect(); + (0..1000).map(|num| PathBuf::from(prefix).join(format!("file {num}.rs"))).collect(); let mut set = HashSet::new(); diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index ebb1d8971b9..225a679efd2 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -607,7 +607,7 @@ mod prim_pointer {} /// /// // This loop prints: 0 1 2 /// for x in array { -/// print!("{} ", x); +/// print!("{x} "); /// } /// ``` /// @@ -646,19 +646,19 @@ mod prim_pointer {} /// // This creates a slice iterator, producing references to each value. /// for item in array.into_iter().enumerate() { /// let (i, x): (usize, &i32) = item; -/// println!("array[{}] = {}", i, x); +/// println!("array[{i}] = {x}"); /// } /// /// // The `array_into_iter` lint suggests this change for future compatibility: /// for item in array.iter().enumerate() { /// let (i, x): (usize, &i32) = item; -/// println!("array[{}] = {}", i, x); +/// println!("array[{i}] = {x}"); /// } /// /// // You can explicitly iterate an array by value using `IntoIterator::into_iter` /// for item in IntoIterator::into_iter(array).enumerate() { /// let (i, x): (usize, i32) = item; -/// println!("array[{}] = {}", i, x); +/// println!("array[{i}] = {x}"); /// } /// ``` /// @@ -673,13 +673,13 @@ mod prim_pointer {} /// // This iterates by reference: /// for item in array.iter().enumerate() { /// let (i, x): (usize, &i32) = item; -/// println!("array[{}] = {}", i, x); +/// println!("array[{i}] = {x}"); /// } /// /// // This iterates by value: /// for item in array.into_iter().enumerate() { /// let (i, x): (usize, i32) = item; -/// println!("array[{}] = {}", i, x); +/// println!("array[{i}] = {x}"); /// } /// ``` /// @@ -702,26 +702,26 @@ mod prim_pointer {} /// // This iterates by reference: /// for item in array.iter() { /// let x: &i32 = item; -/// println!("{}", x); +/// println!("{x}"); /// } /// /// // This iterates by value: /// for item in IntoIterator::into_iter(array) { /// let x: i32 = item; -/// println!("{}", x); +/// println!("{x}"); /// } /// /// // This iterates by value: /// for item in array { /// let x: i32 = item; -/// println!("{}", x); +/// println!("{x}"); /// } /// /// // IntoIter can also start a chain. /// // This iterates by value: /// for item in IntoIterator::into_iter(array).enumerate() { /// let (i, x): (usize, i32) = item; -/// println!("array[{}] = {}", i, x); +/// println!("array[{i}] = {x}"); /// } /// ``` /// diff --git a/library/std/src/process.rs b/library/std/src/process.rs index e3fff155e47..d88ab625371 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -915,7 +915,7 @@ impl Command { /// .status() /// .expect("failed to execute process"); /// - /// println!("process finished with: {}", status); + /// println!("process finished with: {status}"); /// /// assert!(status.success()); /// ``` @@ -1434,7 +1434,7 @@ impl ExitStatus { /// .status() /// .expect("ls could not be executed"); /// - /// println!("ls: {}", status); + /// println!("ls: {status}"); /// status.exit_ok().expect_err("/dev/nonexistent could be listed!"); /// # } // cfg!(unix) /// ``` @@ -1459,7 +1459,7 @@ impl ExitStatus { /// if status.success() { /// println!("'projects/' directory created"); /// } else { - /// println!("failed to create 'projects/' directory: {}", status); + /// println!("failed to create 'projects/' directory: {status}"); /// } /// ``` #[must_use] @@ -1490,7 +1490,7 @@ impl ExitStatus { /// .expect("failed to execute mkdir"); /// /// match status.code() { - /// Some(code) => println!("Exited with status code: {}", code), + /// Some(code) => println!("Exited with status code: {code}"), /// None => println!("Process terminated by signal") /// } /// ``` @@ -1806,13 +1806,13 @@ impl Child { /// let mut child = Command::new("ls").spawn().unwrap(); /// /// match child.try_wait() { - /// Ok(Some(status)) => println!("exited with: {}", status), + /// Ok(Some(status)) => println!("exited with: {status}"), /// Ok(None) => { /// println!("status not ready yet, let's really wait"); /// let res = child.wait(); - /// println!("result: {:?}", res); + /// println!("result: {res:?}"); /// } - /// Err(e) => println!("error attempting to wait: {}", e), + /// Err(e) => println!("error attempting to wait: {e}"), /// } /// ``` #[stable(feature = "process_try_wait", since = "1.18.0")] @@ -1912,7 +1912,7 @@ impl Child { /// std::process::exit(match run_app() { /// Ok(_) => 0, /// Err(err) => { -/// eprintln!("error: {:?}", err); +/// eprintln!("error: {err:?}"); /// 1 /// } /// }); @@ -2071,7 +2071,7 @@ impl Termination for ! { impl<E: fmt::Debug> Termination for Result<!, E> { fn report(self) -> ExitCode { let Err(err) = self; - eprintln!("Error: {:?}", err); + eprintln!("Error: {err:?}"); ExitCode::FAILURE.report() } } diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs index e5cdc473706..4f779ab4e78 100644 --- a/library/std/src/process/tests.rs +++ b/library/std/src/process/tests.rs @@ -64,7 +64,7 @@ fn signal_reported_right() { p.kill().unwrap(); match p.wait().unwrap().signal() { Some(9) => {} - result => panic!("not terminated by signal 9 (instead, {:?})", result), + result => panic!("not terminated by signal 9 (instead, {result:?})"), } } @@ -252,8 +252,7 @@ fn test_override_env() { assert!( output.contains("RUN_TEST_NEW_ENV=123"), - "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", - output + "didn't find RUN_TEST_NEW_ENV inside of:\n\n{output}", ); } @@ -265,8 +264,7 @@ fn test_add_to_env() { assert!( output.contains("RUN_TEST_NEW_ENV=123"), - "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", - output + "didn't find RUN_TEST_NEW_ENV inside of:\n\n{output}" ); } @@ -288,13 +286,11 @@ fn test_capture_env_at_spawn() { assert!( output.contains("RUN_TEST_NEW_ENV1=123"), - "didn't find RUN_TEST_NEW_ENV1 inside of:\n\n{}", - output + "didn't find RUN_TEST_NEW_ENV1 inside of:\n\n{output}" ); assert!( output.contains("RUN_TEST_NEW_ENV2=456"), - "didn't find RUN_TEST_NEW_ENV2 inside of:\n\n{}", - output + "didn't find RUN_TEST_NEW_ENV2 inside of:\n\n{output}" ); } diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs index ee35598bab5..87d01daeafc 100644 --- a/library/std/src/sync/mod.rs +++ b/library/std/src/sync/mod.rs @@ -19,7 +19,7 @@ //! B = 4; //! A = A + B; //! C = B; -//! println!("{} {} {}", A, B, C); +//! println!("{A} {B} {C}"); //! C = A; //! } //! } diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs index 2e54321e127..e85a8723965 100644 --- a/library/std/src/sync/mpsc/mod.rs +++ b/library/std/src/sync/mpsc/mod.rs @@ -129,7 +129,7 @@ //! //! // Unbounded receiver waiting for all senders to complete. //! while let Ok(msg) = rx.recv() { -//! println!("{}", msg); +//! println!("{msg}"); //! } //! //! println!("completed"); @@ -376,7 +376,7 @@ impl<T> !Sync for Receiver<T> {} /// }); /// /// for x in recv.iter() { -/// println!("Got: {}", x); +/// println!("Got: {x}"); /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -419,7 +419,7 @@ pub struct Iter<'a, T: 'a> { /// thread::sleep(Duration::from_secs(2)); // block for two seconds /// /// for x in receiver.try_iter() { -/// println!("Got: {}", x); +/// println!("Got: {x}"); /// } /// ``` #[stable(feature = "receiver_try_iter", since = "1.15.0")] @@ -453,7 +453,7 @@ pub struct TryIter<'a, T: 'a> { /// }); /// /// for x in recv.into_iter() { -/// println!("Got: {}", x); +/// println!("Got: {x}"); /// } /// ``` #[stable(feature = "receiver_into_iter", since = "1.1.0")] @@ -544,16 +544,16 @@ impl<T> !Sync for Sender<T> {} /// let mut msg; /// /// msg = receiver.recv().unwrap(); -/// println!("message {} received", msg); +/// println!("message {msg} received"); /// /// // "Thread unblocked!" will be printed now /// /// msg = receiver.recv().unwrap(); -/// println!("message {} received", msg); +/// println!("message {msg} received"); /// /// msg = receiver.recv().unwrap(); /// -/// println!("message {} received", msg); +/// println!("message {msg} received"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct SyncSender<T> { @@ -996,14 +996,14 @@ impl<T> SyncSender<T> { /// /// let mut msg; /// msg = receiver.recv().unwrap(); - /// println!("message {} received", msg); + /// println!("message {msg} received"); /// /// msg = receiver.recv().unwrap(); - /// println!("message {} received", msg); + /// println!("message {msg} received"); /// /// // Third message may have never been sent /// match receiver.try_recv() { - /// Ok(msg) => println!("message {} received", msg), + /// Ok(msg) => println!("message {msg} received"), /// Err(_) => println!("the third message was never sent"), /// } /// ``` diff --git a/library/std/src/sync/mpsc/shared.rs b/library/std/src/sync/mpsc/shared.rs index 8487a5f8b50..56162655544 100644 --- a/library/std/src/sync/mpsc/shared.rs +++ b/library/std/src/sync/mpsc/shared.rs @@ -369,7 +369,7 @@ impl<T> Packet<T> { match self.channels.fetch_sub(1, Ordering::SeqCst) { 1 => {} n if n > 1 => return, - n => panic!("bad number of channels left {}", n), + n => panic!("bad number of channels left {n}"), } match self.cnt.swap(DISCONNECTED, Ordering::SeqCst) { diff --git a/library/std/src/sync/mutex/tests.rs b/library/std/src/sync/mutex/tests.rs index a1b5aeddcb6..93900566f11 100644 --- a/library/std/src/sync/mutex/tests.rs +++ b/library/std/src/sync/mutex/tests.rs @@ -94,7 +94,7 @@ fn test_into_inner_poison() { assert!(m.is_poisoned()); match Arc::try_unwrap(m).unwrap().into_inner() { Err(e) => assert_eq!(e.into_inner(), NonCopy(10)), - Ok(x) => panic!("into_inner of poisoned Mutex is Ok: {:?}", x), + Ok(x) => panic!("into_inner of poisoned Mutex is Ok: {x:?}"), } } @@ -118,7 +118,7 @@ fn test_get_mut_poison() { assert!(m.is_poisoned()); match Arc::try_unwrap(m).unwrap().get_mut() { Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)), - Ok(x) => panic!("get_mut of poisoned Mutex is Ok: {:?}", x), + Ok(x) => panic!("get_mut of poisoned Mutex is Ok: {x:?}"), } } diff --git a/library/std/src/sync/once.rs b/library/std/src/sync/once.rs index f76d0759561..511de863dc5 100644 --- a/library/std/src/sync/once.rs +++ b/library/std/src/sync/once.rs @@ -256,6 +256,7 @@ impl Once { /// /// [poison]: struct.Mutex.html#poisoning #[stable(feature = "rust1", since = "1.0.0")] + #[track_caller] pub fn call_once<F>(&self, f: F) where F: FnOnce(), @@ -390,6 +391,7 @@ impl Once { // currently no way to take an `FnOnce` and call it via virtual dispatch // without some allocation overhead. #[cold] + #[track_caller] fn call_inner(&self, ignore_poisoning: bool, init: &mut dyn FnMut(&OnceState)) { let mut state_and_queue = self.state_and_queue.load(Ordering::Acquire); loop { diff --git a/library/std/src/sync/poison.rs b/library/std/src/sync/poison.rs index fa950331e64..07a90da449c 100644 --- a/library/std/src/sync/poison.rs +++ b/library/std/src/sync/poison.rs @@ -73,7 +73,7 @@ pub struct Guard { /// Ok(_) => unreachable!(), /// Err(p_err) => { /// let data = p_err.get_ref(); -/// println!("recovered: {}", data); +/// println!("recovered: {data}"); /// } /// }; /// ``` diff --git a/library/std/src/sync/rwlock/tests.rs b/library/std/src/sync/rwlock/tests.rs index e9b74fb3ecc..53aa2b1e38a 100644 --- a/library/std/src/sync/rwlock/tests.rs +++ b/library/std/src/sync/rwlock/tests.rs @@ -218,7 +218,7 @@ fn test_into_inner_poison() { assert!(m.is_poisoned()); match Arc::try_unwrap(m).unwrap().into_inner() { Err(e) => assert_eq!(e.into_inner(), NonCopy(10)), - Ok(x) => panic!("into_inner of poisoned RwLock is Ok: {:?}", x), + Ok(x) => panic!("into_inner of poisoned RwLock is Ok: {x:?}"), } } @@ -242,6 +242,6 @@ fn test_get_mut_poison() { assert!(m.is_poisoned()); match Arc::try_unwrap(m).unwrap().get_mut() { Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)), - Ok(x) => panic!("get_mut of poisoned RwLock is Ok: {:?}", x), + Ok(x) => panic!("get_mut of poisoned RwLock is Ok: {x:?}"), } } diff --git a/library/std/src/sys/common/alloc.rs b/library/std/src/sys/common/alloc.rs index e06eaf6db1a..e8e7c51cb9b 100644 --- a/library/std/src/sys/common/alloc.rs +++ b/library/std/src/sys/common/alloc.rs @@ -28,7 +28,7 @@ pub const MIN_ALIGN: usize = 8; target_arch = "wasm64", )))] pub const MIN_ALIGN: usize = 16; -// The allocator on the esp-idf platform guarentees 4 byte alignment. +// The allocator on the esp-idf platform guarantees 4 byte alignment. #[cfg(all(any( all(target_arch = "riscv32", target_os = "espidf"), all(target_arch = "xtensa", target_os = "espidf"), diff --git a/library/std/src/sys/hermit/fd.rs b/library/std/src/sys/hermit/fd.rs index 1179a49c22f..c400f5f2c2e 100644 --- a/library/std/src/sys/hermit/fd.rs +++ b/library/std/src/sys/hermit/fd.rs @@ -1,6 +1,6 @@ #![unstable(reason = "not public", issue = "none", feature = "fd")] -use crate::io::{self, Read, ReadBuf}; +use crate::io::{self, Read}; use crate::mem; use crate::sys::cvt; use crate::sys::hermit::abi; diff --git a/library/std/src/sys/sgx/abi/mod.rs b/library/std/src/sys/sgx/abi/mod.rs index 5df08a4ff59..9508c387415 100644 --- a/library/std/src/sys/sgx/abi/mod.rs +++ b/library/std/src/sys/sgx/abi/mod.rs @@ -95,7 +95,7 @@ extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64 pub(super) fn exit_with_code(code: isize) -> ! { if code != 0 { if let Some(mut out) = panic::SgxPanicOutput::new() { - let _ = write!(out, "Exited with status code {}", code); + let _ = write!(out, "Exited with status code {code}"); } } usercalls::exit(code != 0); diff --git a/library/std/src/sys/sgx/abi/usercalls/mod.rs b/library/std/src/sys/sgx/abi/usercalls/mod.rs index a6a659df291..4030355f135 100644 --- a/library/std/src/sys/sgx/abi/usercalls/mod.rs +++ b/library/std/src/sys/sgx/abi/usercalls/mod.rs @@ -83,7 +83,7 @@ pub fn close(fd: Fd) { fn string_from_bytebuffer(buf: &alloc::UserRef<ByteBuffer>, usercall: &str, arg: &str) -> String { String::from_utf8(buf.copy_user_buffer()) - .unwrap_or_else(|_| rtabort!("Usercall {}: expected {} to be valid UTF-8", usercall, arg)) + .unwrap_or_else(|_| rtabort!("Usercall {usercall}: expected {arg} to be valid UTF-8")) } /// Usercall `bind_stream`. See the ABI documentation for more information. @@ -287,7 +287,7 @@ fn check_os_error(err: Result) -> i32 { { err } else { - rtabort!("Usercall: returned invalid error value {}", err) + rtabort!("Usercall: returned invalid error value {err}") } } diff --git a/library/std/src/sys/sgx/abi/usercalls/raw.rs b/library/std/src/sys/sgx/abi/usercalls/raw.rs index b0e6a6aaed7..4267b96ccd5 100644 --- a/library/std/src/sys/sgx/abi/usercalls/raw.rs +++ b/library/std/src/sys/sgx/abi/usercalls/raw.rs @@ -132,7 +132,7 @@ impl<T: RegisterArgument> RegisterArgument for Option<NonNull<T>> { impl ReturnValue for ! { fn from_registers(call: &'static str, _regs: (Register, Register)) -> Self { - rtabort!("Usercall {}: did not expect to be re-entered", call); + rtabort!("Usercall {call}: did not expect to be re-entered"); } } diff --git a/library/std/src/sys/sgx/net.rs b/library/std/src/sys/sgx/net.rs index d14990c6877..feb0b62dcd1 100644 --- a/library/std/src/sys/sgx/net.rs +++ b/library/std/src/sys/sgx/net.rs @@ -501,7 +501,7 @@ impl<'a> TryFrom<(&'a str, u16)> for LookupHost { type Error = io::Error; fn try_from((host, port): (&'a str, u16)) -> io::Result<LookupHost> { - LookupHost::new(format!("{}:{}", host, port)) + LookupHost::new(format!("{host}:{port}")) } } diff --git a/library/std/src/sys/sgx/os.rs b/library/std/src/sys/sgx/os.rs index 5f8b8def7c6..5da0257f35d 100644 --- a/library/std/src/sys/sgx/os.rs +++ b/library/std/src/sys/sgx/os.rs @@ -22,7 +22,7 @@ pub fn error_string(errno: i32) -> String { if errno == RESULT_SUCCESS { "operation successful".into() } else if ((Error::UserRangeStart as _)..=(Error::UserRangeEnd as _)).contains(&errno) { - format!("user-specified error {:08x}", errno) + format!("user-specified error {errno:08x}") } else { decode_error_kind(errno).as_str().into() } diff --git a/library/std/src/sys/sgx/stdio.rs b/library/std/src/sys/sgx/stdio.rs index 8ccf043b5b5..2e680e740fd 100644 --- a/library/std/src/sys/sgx/stdio.rs +++ b/library/std/src/sys/sgx/stdio.rs @@ -83,6 +83,6 @@ pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) { } let buf = unsafe { slice::from_raw_parts(m as *const u8, s as _) }; if let Ok(s) = str::from_utf8(&buf[..buf.iter().position(|&b| b == 0).unwrap_or(buf.len())]) { - eprint!("{}", s); + eprint!("{s}"); } } diff --git a/library/std/src/sys/solid/fs.rs b/library/std/src/sys/solid/fs.rs index a6ed10f7789..a2cbee4dcf0 100644 --- a/library/std/src/sys/solid/fs.rs +++ b/library/std/src/sys/solid/fs.rs @@ -289,7 +289,26 @@ impl OpenOptions { } fn cstr(path: &Path) -> io::Result<CString> { - Ok(CString::new(path.as_os_str().as_bytes())?) + let path = path.as_os_str().as_bytes(); + + if !path.starts_with(br"\") { + // Relative paths aren't supported + return Err(crate::io::const_io_error!( + crate::io::ErrorKind::Unsupported, + "relative path is not supported on this platform", + )); + } + + // Apply the thread-safety wrapper + const SAFE_PREFIX: &[u8] = br"\TS"; + let wrapped_path = [SAFE_PREFIX, &path, &[0]].concat(); + + CString::from_vec_with_nul(wrapped_path).map_err(|_| { + crate::io::const_io_error!( + io::ErrorKind::InvalidInput, + "path provided contains a nul byte", + ) + }) } impl File { diff --git a/library/std/src/sys/solid/mod.rs b/library/std/src/sys/solid/mod.rs index 2082c940153..049460755d6 100644 --- a/library/std/src/sys/solid/mod.rs +++ b/library/std/src/sys/solid/mod.rs @@ -87,7 +87,7 @@ pub fn hashmap_random_keys() -> (u64, u64) { unsafe { let mut out = crate::mem::MaybeUninit::<[u64; 2]>::uninit(); let result = abi::SOLID_RNG_SampleRandomBytes(out.as_mut_ptr() as *mut u8, 16); - assert_eq!(result, 0, "SOLID_RNG_SampleRandomBytes failed: {}", result); + assert_eq!(result, 0, "SOLID_RNG_SampleRandomBytes failed: {result}"); let [x1, x2] = out.assume_init(); (x1, x2) } diff --git a/library/std/src/sys/solid/net.rs b/library/std/src/sys/solid/net.rs index a43407bd0f8..faeda5a854d 100644 --- a/library/std/src/sys/solid/net.rs +++ b/library/std/src/sys/solid/net.rs @@ -157,7 +157,7 @@ pub fn cvt_gai(err: c_int) -> io::Result<()> { }; Err(io::Error::new( io::ErrorKind::Uncategorized, - &format!("failed to lookup address information: {}", msg)[..], + &format!("failed to lookup address information: {msg}")[..], )) } } diff --git a/library/std/src/sys/solid/os.rs b/library/std/src/sys/solid/os.rs index 22239e1fa8e..127cca3acca 100644 --- a/library/std/src/sys/solid/os.rs +++ b/library/std/src/sys/solid/os.rs @@ -26,7 +26,7 @@ pub fn errno() -> i32 { } pub fn error_string(errno: i32) -> String { - if let Some(name) = error::error_name(errno) { name.to_owned() } else { format!("{}", errno) } + if let Some(name) = error::error_name(errno) { name.to_owned() } else { format!("{errno}") } } pub fn getcwd() -> io::Result<PathBuf> { diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 8bd0b9b14af..a3e6b081936 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -228,23 +228,54 @@ struct Dir(*mut libc::DIR); unsafe impl Send for Dir {} unsafe impl Sync for Dir {} +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "solaris", + target_os = "illumos", + target_os = "fuchsia", + target_os = "redox" +))] pub struct DirEntry { - entry: dirent64, dir: Arc<InnerReadDir>, + entry: dirent64_min, // We need to store an owned copy of the entry name on platforms that use // readdir() (not readdir_r()), because a) struct dirent may use a flexible // array to store the name, b) it lives only until the next readdir() call. - #[cfg(any( - target_os = "android", - target_os = "linux", - target_os = "solaris", - target_os = "illumos", - target_os = "fuchsia", - target_os = "redox" - ))] name: CString, } +// Define a minimal subset of fields we need from `dirent64`, especially since +// we're not using the immediate `d_name` on these targets. Keeping this as an +// `entry` field in `DirEntry` helps reduce the `cfg` boilerplate elsewhere. +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "solaris", + target_os = "illumos", + target_os = "fuchsia", + target_os = "redox" +))] +struct dirent64_min { + d_ino: u64, + #[cfg(not(any(target_os = "solaris", target_os = "illumos")))] + d_type: u8, +} + +#[cfg(not(any( + target_os = "android", + target_os = "linux", + target_os = "solaris", + target_os = "illumos", + target_os = "fuchsia", + target_os = "redox" +)))] +pub struct DirEntry { + dir: Arc<InnerReadDir>, + // The full entry includes a fixed-length `d_name`. + entry: dirent64, +} + #[derive(Clone, Debug)] pub struct OpenOptions { // generic @@ -491,11 +522,21 @@ impl Iterator for ReadDir { // Only d_reclen bytes of *entry_ptr are valid, so we can't just copy the // whole thing (#93384). Instead, copy everything except the name. + let mut copy: dirent64 = mem::zeroed(); + // Can't dereference entry_ptr, so use the local entry to get + // offsetof(struct dirent, d_name) + let copy_bytes = &mut copy as *mut _ as *mut u8; + let copy_name = &mut copy.d_name as *mut _ as *mut u8; + let name_offset = copy_name.offset_from(copy_bytes) as usize; let entry_bytes = entry_ptr as *const u8; - let entry_name = ptr::addr_of!((*entry_ptr).d_name) as *const u8; - let name_offset = entry_name.offset_from(entry_bytes) as usize; - let mut entry: dirent64 = mem::zeroed(); - ptr::copy_nonoverlapping(entry_bytes, &mut entry as *mut _ as *mut u8, name_offset); + let entry_name = entry_bytes.add(name_offset); + ptr::copy_nonoverlapping(entry_bytes, copy_bytes, name_offset); + + let entry = dirent64_min { + d_ino: copy.d_ino as u64, + #[cfg(not(any(target_os = "solaris", target_os = "illumos")))] + d_type: copy.d_type as u8, + }; let ret = DirEntry { entry, @@ -1482,140 +1523,60 @@ mod remove_dir_impl { pub use crate::sys_common::fs::remove_dir_all; } -// Dynamically choose implementation Macos x86-64: modern for 10.10+, fallback for older versions -#[cfg(all(target_os = "macos", target_arch = "x86_64"))] +// Modern implementation using openat(), unlinkat() and fdopendir() +#[cfg(not(any(target_os = "redox", target_os = "espidf")))] mod remove_dir_impl { - use super::{cstr, lstat, Dir, InnerReadDir, ReadDir}; + use super::{cstr, lstat, Dir, DirEntry, InnerReadDir, ReadDir}; use crate::ffi::CStr; use crate::io; use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd}; use crate::os::unix::prelude::{OwnedFd, RawFd}; use crate::path::{Path, PathBuf}; use crate::sync::Arc; - use crate::sys::weak::weak; use crate::sys::{cvt, cvt_r}; - use libc::{c_char, c_int, DIR}; - pub fn openat_nofollow_dironly(parent_fd: Option<RawFd>, p: &CStr) -> io::Result<OwnedFd> { - weak!(fn openat(c_int, *const c_char, c_int) -> c_int); - let fd = cvt_r(|| unsafe { - openat.get().unwrap()( - parent_fd.unwrap_or(libc::AT_FDCWD), - p.as_ptr(), - libc::O_CLOEXEC | libc::O_RDONLY | libc::O_NOFOLLOW | libc::O_DIRECTORY, - ) - })?; - Ok(unsafe { OwnedFd::from_raw_fd(fd) }) - } - - fn fdreaddir(dir_fd: OwnedFd) -> io::Result<(ReadDir, RawFd)> { - weak!(fn fdopendir(c_int) -> *mut DIR, "fdopendir$INODE64"); - let ptr = unsafe { fdopendir.get().unwrap()(dir_fd.as_raw_fd()) }; - if ptr.is_null() { - return Err(io::Error::last_os_error()); - } - let dirp = Dir(ptr); - // file descriptor is automatically closed by libc::closedir() now, so give up ownership - let new_parent_fd = dir_fd.into_raw_fd(); - // a valid root is not needed because we do not call any functions involving the full path - // of the DirEntrys. - let dummy_root = PathBuf::new(); - Ok(( - ReadDir { - inner: Arc::new(InnerReadDir { dirp, root: dummy_root }), - end_of_stream: false, - }, - new_parent_fd, - )) - } - - fn remove_dir_all_recursive(parent_fd: Option<RawFd>, p: &Path) -> io::Result<()> { - weak!(fn unlinkat(c_int, *const c_char, c_int) -> c_int); + #[cfg(not(all(target_os = "macos", target_arch = "x86_64"),))] + use libc::{fdopendir, openat, unlinkat}; + #[cfg(all(target_os = "macos", target_arch = "x86_64"))] + use macos_weak::{fdopendir, openat, unlinkat}; - let pcstr = cstr(p)?; + #[cfg(all(target_os = "macos", target_arch = "x86_64"))] + mod macos_weak { + use crate::sys::weak::weak; + use libc::{c_char, c_int, DIR}; - // entry is expected to be a directory, open as such - let fd = openat_nofollow_dironly(parent_fd, &pcstr)?; + fn get_openat_fn() -> Option<unsafe extern "C" fn(c_int, *const c_char, c_int) -> c_int> { + weak!(fn openat(c_int, *const c_char, c_int) -> c_int); + openat.get() + } - // open the directory passing ownership of the fd - let (dir, fd) = fdreaddir(fd)?; - for child in dir { - let child = child?; - match child.entry.d_type { - libc::DT_DIR => { - remove_dir_all_recursive(Some(fd), Path::new(&child.file_name()))?; - } - libc::DT_UNKNOWN => { - match cvt(unsafe { unlinkat.get().unwrap()(fd, child.name_cstr().as_ptr(), 0) }) - { - // type unknown - try to unlink - Err(err) if err.raw_os_error() == Some(libc::EPERM) => { - // if the file is a directory unlink fails with EPERM - remove_dir_all_recursive(Some(fd), Path::new(&child.file_name()))?; - } - result => { - result?; - } - } - } - _ => { - // not a directory -> unlink - cvt(unsafe { unlinkat.get().unwrap()(fd, child.name_cstr().as_ptr(), 0) })?; - } - } + pub fn has_openat() -> bool { + get_openat_fn().is_some() } - // unlink the directory after removing its contents - cvt(unsafe { - unlinkat.get().unwrap()( - parent_fd.unwrap_or(libc::AT_FDCWD), - pcstr.as_ptr(), - libc::AT_REMOVEDIR, - ) - })?; - Ok(()) - } + pub unsafe fn openat(dirfd: c_int, pathname: *const c_char, flags: c_int) -> c_int { + get_openat_fn().map(|openat| openat(dirfd, pathname, flags)).unwrap_or_else(|| { + crate::sys::unix::os::set_errno(libc::ENOSYS); + -1 + }) + } - fn remove_dir_all_modern(p: &Path) -> io::Result<()> { - // We cannot just call remove_dir_all_recursive() here because that would not delete a passed - // symlink. No need to worry about races, because remove_dir_all_recursive() does not recurse - // into symlinks. - let attr = lstat(p)?; - if attr.file_type().is_symlink() { - crate::fs::remove_file(p) - } else { - remove_dir_all_recursive(None, p) + pub unsafe fn fdopendir(fd: c_int) -> *mut DIR { + weak!(fn fdopendir(c_int) -> *mut DIR, "fdopendir$INODE64"); + fdopendir.get().map(|fdopendir| fdopendir(fd)).unwrap_or_else(|| { + crate::sys::unix::os::set_errno(libc::ENOSYS); + crate::ptr::null_mut() + }) } - } - pub fn remove_dir_all(p: &Path) -> io::Result<()> { - weak!(fn openat(c_int, *const c_char, c_int) -> c_int); - if openat.get().is_some() { - // openat() is available with macOS 10.10+, just like unlinkat() and fdopendir() - remove_dir_all_modern(p) - } else { - // fall back to classic implementation - crate::sys_common::fs::remove_dir_all(p) + pub unsafe fn unlinkat(dirfd: c_int, pathname: *const c_char, flags: c_int) -> c_int { + weak!(fn unlinkat(c_int, *const c_char, c_int) -> c_int); + unlinkat.get().map(|unlinkat| unlinkat(dirfd, pathname, flags)).unwrap_or_else(|| { + crate::sys::unix::os::set_errno(libc::ENOSYS); + -1 + }) } } -} - -// Modern implementation using openat(), unlinkat() and fdopendir() -#[cfg(not(any( - all(target_os = "macos", target_arch = "x86_64"), - target_os = "redox", - target_os = "espidf" -)))] -mod remove_dir_impl { - use super::{cstr, lstat, Dir, DirEntry, InnerReadDir, ReadDir}; - use crate::ffi::CStr; - use crate::io; - use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd}; - use crate::os::unix::prelude::{OwnedFd, RawFd}; - use crate::path::{Path, PathBuf}; - use crate::sync::Arc; - use crate::sys::{cvt, cvt_r}; - use libc::{fdopendir, openat, unlinkat}; pub fn openat_nofollow_dironly(parent_fd: Option<RawFd>, p: &CStr) -> io::Result<OwnedFd> { let fd = cvt_r(|| unsafe { @@ -1680,47 +1641,53 @@ mod remove_dir_impl { } } - fn remove_dir_all_recursive(parent_fd: Option<RawFd>, p: &Path) -> io::Result<()> { - let pcstr = cstr(p)?; - - // entry is expected to be a directory, open as such - let fd = openat_nofollow_dironly(parent_fd, &pcstr)?; + fn remove_dir_all_recursive(parent_fd: Option<RawFd>, path: &CStr) -> io::Result<()> { + // try opening as directory + let fd = match openat_nofollow_dironly(parent_fd, &path) { + Err(err) if err.raw_os_error() == Some(libc::ENOTDIR) => { + // not a directory - don't traverse further + return match parent_fd { + // unlink... + Some(parent_fd) => { + cvt(unsafe { unlinkat(parent_fd, path.as_ptr(), 0) }).map(drop) + } + // ...unless this was supposed to be the deletion root directory + None => Err(err), + }; + } + result => result?, + }; // open the directory passing ownership of the fd let (dir, fd) = fdreaddir(fd)?; for child in dir { let child = child?; + let child_name = child.name_cstr(); match is_dir(&child) { Some(true) => { - remove_dir_all_recursive(Some(fd), Path::new(&child.file_name()))?; + remove_dir_all_recursive(Some(fd), child_name)?; } Some(false) => { - cvt(unsafe { unlinkat(fd, child.name_cstr().as_ptr(), 0) })?; + cvt(unsafe { unlinkat(fd, child_name.as_ptr(), 0) })?; + } + None => { + // POSIX specifies that calling unlink()/unlinkat(..., 0) on a directory can succeed + // if the process has the appropriate privileges. This however can causing orphaned + // directories requiring an fsck e.g. on Solaris and Illumos. So we try recursing + // into it first instead of trying to unlink() it. + remove_dir_all_recursive(Some(fd), child_name)?; } - None => match cvt(unsafe { unlinkat(fd, child.name_cstr().as_ptr(), 0) }) { - // type unknown - try to unlink - Err(err) - if err.raw_os_error() == Some(libc::EISDIR) - || err.raw_os_error() == Some(libc::EPERM) => - { - // if the file is a directory unlink fails with EISDIR on Linux and EPERM everyhwere else - remove_dir_all_recursive(Some(fd), Path::new(&child.file_name()))?; - } - result => { - result?; - } - }, } } // unlink the directory after removing its contents cvt(unsafe { - unlinkat(parent_fd.unwrap_or(libc::AT_FDCWD), pcstr.as_ptr(), libc::AT_REMOVEDIR) + unlinkat(parent_fd.unwrap_or(libc::AT_FDCWD), path.as_ptr(), libc::AT_REMOVEDIR) })?; Ok(()) } - pub fn remove_dir_all(p: &Path) -> io::Result<()> { + fn remove_dir_all_modern(p: &Path) -> io::Result<()> { // We cannot just call remove_dir_all_recursive() here because that would not delete a passed // symlink. No need to worry about races, because remove_dir_all_recursive() does not recurse // into symlinks. @@ -1728,7 +1695,23 @@ mod remove_dir_impl { if attr.file_type().is_symlink() { crate::fs::remove_file(p) } else { - remove_dir_all_recursive(None, p) + remove_dir_all_recursive(None, &cstr(p)?) + } + } + + #[cfg(not(all(target_os = "macos", target_arch = "x86_64")))] + pub fn remove_dir_all(p: &Path) -> io::Result<()> { + remove_dir_all_modern(p) + } + + #[cfg(all(target_os = "macos", target_arch = "x86_64"))] + pub fn remove_dir_all(p: &Path) -> io::Result<()> { + if macos_weak::has_openat() { + // openat() is available with macOS 10.10+, just like unlinkat() and fdopendir() + remove_dir_all_modern(p) + } else { + // fall back to classic implementation + crate::sys_common::fs::remove_dir_all(p) } } } diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index 61c15ecd85d..e6fd9a0c827 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -54,7 +54,7 @@ pub fn cvt_gai(err: c_int) -> io::Result<()> { Err(io::Error::new( io::ErrorKind::Uncategorized, - &format!("failed to lookup address information: {}", detail)[..], + &format!("failed to lookup address information: {detail}")[..], )) } diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs index b268ef5c364..0b6cdb923bd 100644 --- a/library/std/src/sys/unix/os.rs +++ b/library/std/src/sys/unix/os.rs @@ -384,11 +384,8 @@ pub fn current_exe() -> io::Result<PathBuf> { if let Ok(path) = crate::fs::read_link("/proc/self/path/a.out") { Ok(path) } else { - extern "C" { - fn getexecname() -> *const c_char; - } unsafe { - let path = getexecname(); + let path = libc::getexecname(); if path.is_null() { Err(io::Error::last_os_error()) } else { diff --git a/library/std/src/sys/unix/os_str/tests.rs b/library/std/src/sys/unix/os_str/tests.rs index 37967378155..213277f01f2 100644 --- a/library/std/src/sys/unix/os_str/tests.rs +++ b/library/std/src/sys/unix/os_str/tests.rs @@ -4,7 +4,7 @@ use super::*; fn slice_debug_output() { let input = Slice::from_u8_slice(b"\xF0hello,\tworld"); let expected = r#""\xF0hello,\tworld""#; - let output = format!("{:?}", input); + let output = format!("{input:?}"); assert_eq!(output, expected); } diff --git a/library/std/src/sys/unix/path.rs b/library/std/src/sys/unix/path.rs index 6d6f4c8b8dc..a98a69e2db8 100644 --- a/library/std/src/sys/unix/path.rs +++ b/library/std/src/sys/unix/path.rs @@ -28,7 +28,8 @@ pub(crate) fn absolute(path: &Path) -> io::Result<PathBuf> { // See 4.13 Pathname Resolution, IEEE Std 1003.1-2017 // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13 - let mut components = path.components(); + // Get the components, skipping the redundant leading "." component if it exists. + let mut components = path.strip_prefix(".").unwrap_or(path).components(); let path_os = path.as_os_str().bytes(); let mut normalized = if path.is_absolute() { diff --git a/library/std/src/sys/unix/process/process_fuchsia.rs b/library/std/src/sys/unix/process/process_fuchsia.rs index 09bfd9680f5..e3347ab12a7 100644 --- a/library/std/src/sys/unix/process/process_fuchsia.rs +++ b/library/std/src/sys/unix/process/process_fuchsia.rs @@ -211,7 +211,7 @@ impl Process { return Ok(None); } _ => { - panic!("Failed to wait on process handle: {}", status); + panic!("Failed to wait on process handle: {status}"); } } zx_cvt(zx_object_get_info( diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 9fc2d9fce4d..9d2803b40c4 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -3,11 +3,11 @@ use crate::fmt; use crate::io::{self, Error, ErrorKind}; use crate::mem; use crate::num::NonZeroI32; -use crate::os::raw::NonZero_c_int; use crate::ptr; use crate::sys; use crate::sys::cvt; use crate::sys::process::process_common::*; +use core::ffi::NonZero_c_int; #[cfg(target_os = "linux")] use crate::os::linux::process::PidFd; @@ -120,7 +120,7 @@ impl Command { Err(ref e) if e.kind() == ErrorKind::Interrupted => {} Err(e) => { assert!(p.wait().is_ok(), "wait() should either return Ok or panic"); - panic!("the CLOEXEC pipe failed: {:?}", e) + panic!("the CLOEXEC pipe failed: {e:?}") } Ok(..) => { // pipe I/O up to PIPE_BUF bytes should be atomic @@ -648,11 +648,11 @@ impl ExitStatus { } pub fn code(&self) -> Option<i32> { - if self.exited() { Some(libc::WEXITSTATUS(self.0)) } else { None } + self.exited().then(|| libc::WEXITSTATUS(self.0)) } pub fn signal(&self) -> Option<i32> { - if libc::WIFSIGNALED(self.0) { Some(libc::WTERMSIG(self.0)) } else { None } + libc::WIFSIGNALED(self.0).then(|| libc::WTERMSIG(self.0)) } pub fn core_dumped(&self) -> bool { @@ -660,7 +660,7 @@ impl ExitStatus { } pub fn stopped_signal(&self) -> Option<i32> { - if libc::WIFSTOPPED(self.0) { Some(libc::WSTOPSIG(self.0)) } else { None } + libc::WIFSTOPPED(self.0).then(|| libc::WSTOPSIG(self.0)) } pub fn continued(&self) -> bool { @@ -682,15 +682,15 @@ impl From<c_int> for ExitStatus { impl fmt::Display for ExitStatus { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if let Some(code) = self.code() { - write!(f, "exit status: {}", code) + write!(f, "exit status: {code}") } else if let Some(signal) = self.signal() { if self.core_dumped() { - write!(f, "signal: {} (core dumped)", signal) + write!(f, "signal: {signal} (core dumped)") } else { - write!(f, "signal: {}", signal) + write!(f, "signal: {signal}") } } else if let Some(signal) = self.stopped_signal() { - write!(f, "stopped (not terminated) by signal: {}", signal) + write!(f, "stopped (not terminated) by signal: {signal}") } else if self.continued() { write!(f, "continued (WIFCONTINUED)") } else { diff --git a/library/std/src/sys/unix/process/process_unsupported.rs b/library/std/src/sys/unix/process/process_unsupported.rs index 7d549d060fd..bbabdf787d9 100644 --- a/library/std/src/sys/unix/process/process_unsupported.rs +++ b/library/std/src/sys/unix/process/process_unsupported.rs @@ -3,12 +3,12 @@ use crate::fmt; use crate::io; use crate::io::ErrorKind; use crate::num::NonZeroI32; -use crate::os::raw::NonZero_c_int; use crate::sys; use crate::sys::cvt; use crate::sys::pipe::AnonPipe; use crate::sys::process::process_common::*; use crate::sys::unix::unsupported::*; +use core::ffi::NonZero_c_int; use libc::{c_int, pid_t}; diff --git a/library/std/src/sys/unix/process/process_vxworks.rs b/library/std/src/sys/unix/process/process_vxworks.rs index c6714d3aae2..016bc20ec0a 100644 --- a/library/std/src/sys/unix/process/process_vxworks.rs +++ b/library/std/src/sys/unix/process/process_vxworks.rs @@ -2,11 +2,11 @@ use crate::convert::{TryFrom, TryInto}; use crate::fmt; use crate::io::{self, Error, ErrorKind}; use crate::num::NonZeroI32; -use crate::os::raw::NonZero_c_int; use crate::sys; use crate::sys::cvt; use crate::sys::process::process_common::*; use crate::sys_common::thread; +use core::ffi::NonZero_c_int; use libc::RTP_ID; use libc::{self, c_char, c_int}; @@ -239,10 +239,10 @@ impl From<c_int> for ExitStatus { impl fmt::Display for ExitStatus { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if let Some(code) = self.code() { - write!(f, "exit code: {}", code) + write!(f, "exit code: {code}") } else { let signal = self.signal().unwrap(); - write!(f, "signal: {}", signal) + write!(f, "signal: {signal}") } } } diff --git a/library/std/src/sys/unix/rand.rs b/library/std/src/sys/unix/rand.rs index 7a3f6b0d95a..17e8efbe097 100644 --- a/library/std/src/sys/unix/rand.rs +++ b/library/std/src/sys/unix/rand.rs @@ -82,7 +82,7 @@ mod imp { } else if err == libc::EAGAIN { return false; } else { - panic!("unexpected getrandom error: {}", err); + panic!("unexpected getrandom error: {err}"); } } else { read += result as usize; diff --git a/library/std/src/sys/unix/rwlock.rs b/library/std/src/sys/unix/rwlock.rs index b1faf12c226..1318c5b8e3a 100644 --- a/library/std/src/sys/unix/rwlock.rs +++ b/library/std/src/sys/unix/rwlock.rs @@ -48,9 +48,9 @@ impl RWLock { } panic!("rwlock read lock would result in deadlock"); } else { - // According to POSIX, for a properly initialized rwlock this can only - // return EAGAIN or EDEADLK or 0. We rely on that. - debug_assert_eq!(r, 0); + // POSIX does not make guarantees about all the errors that may be returned. + // See issue #94705 for more details. + assert_eq!(r, 0, "unexpected error during rwlock read lock: {:?}", r); self.num_readers.fetch_add(1, Ordering::Relaxed); } } diff --git a/library/std/src/sys/unix/stdio.rs b/library/std/src/sys/unix/stdio.rs index b359987595d..e4d83ba0ffd 100644 --- a/library/std/src/sys/unix/stdio.rs +++ b/library/std/src/sys/unix/stdio.rs @@ -96,7 +96,7 @@ pub fn panic_output() -> Option<impl io::Write> { impl AsFd for io::Stdin { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { - unsafe { BorrowedFd::borrow_raw_fd(libc::STDIN_FILENO) } + unsafe { BorrowedFd::borrow_raw(libc::STDIN_FILENO) } } } @@ -104,7 +104,7 @@ impl AsFd for io::Stdin { impl<'a> AsFd for io::StdinLock<'a> { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { - unsafe { BorrowedFd::borrow_raw_fd(libc::STDIN_FILENO) } + unsafe { BorrowedFd::borrow_raw(libc::STDIN_FILENO) } } } @@ -112,7 +112,7 @@ impl<'a> AsFd for io::StdinLock<'a> { impl AsFd for io::Stdout { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { - unsafe { BorrowedFd::borrow_raw_fd(libc::STDOUT_FILENO) } + unsafe { BorrowedFd::borrow_raw(libc::STDOUT_FILENO) } } } @@ -120,7 +120,7 @@ impl AsFd for io::Stdout { impl<'a> AsFd for io::StdoutLock<'a> { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { - unsafe { BorrowedFd::borrow_raw_fd(libc::STDOUT_FILENO) } + unsafe { BorrowedFd::borrow_raw(libc::STDOUT_FILENO) } } } @@ -128,7 +128,7 @@ impl<'a> AsFd for io::StdoutLock<'a> { impl AsFd for io::Stderr { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { - unsafe { BorrowedFd::borrow_raw_fd(libc::STDERR_FILENO) } + unsafe { BorrowedFd::borrow_raw(libc::STDERR_FILENO) } } } @@ -136,6 +136,6 @@ impl AsFd for io::Stderr { impl<'a> AsFd for io::StderrLock<'a> { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { - unsafe { BorrowedFd::borrow_raw_fd(libc::STDERR_FILENO) } + unsafe { BorrowedFd::borrow_raw(libc::STDERR_FILENO) } } } diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index cf8cf5ad49f..2d5d306ed62 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -279,10 +279,15 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> { ))] { #[cfg(any(target_os = "android", target_os = "linux"))] { + let quota = cgroup2_quota().max(1); let mut set: libc::cpu_set_t = unsafe { mem::zeroed() }; - if unsafe { libc::sched_getaffinity(0, mem::size_of::<libc::cpu_set_t>(), &mut set) } == 0 { - let count = unsafe { libc::CPU_COUNT(&set) }; - return Ok(unsafe { NonZeroUsize::new_unchecked(count as usize) }); + unsafe { + if libc::sched_getaffinity(0, mem::size_of::<libc::cpu_set_t>(), &mut set) == 0 { + let count = libc::CPU_COUNT(&set) as usize; + let count = count.min(quota); + // SAFETY: affinity mask can't be empty and the quota gets clamped to a minimum of 1 + return Ok(NonZeroUsize::new_unchecked(count)); + } } } match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } { @@ -368,6 +373,85 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> { } } +/// Returns cgroup CPU quota in core-equivalents, rounded down, or usize::MAX if the quota cannot +/// be determined or is not set. +#[cfg(any(target_os = "android", target_os = "linux"))] +fn cgroup2_quota() -> usize { + use crate::ffi::OsString; + use crate::fs::{try_exists, File}; + use crate::io::Read; + use crate::os::unix::ffi::OsStringExt; + use crate::path::PathBuf; + + let mut quota = usize::MAX; + if cfg!(miri) { + // Attempting to open a file fails under default flags due to isolation. + // And Miri does not have parallelism anyway. + return quota; + } + + let _: Option<()> = try { + let mut buf = Vec::with_capacity(128); + // find our place in the cgroup hierarchy + File::open("/proc/self/cgroup").ok()?.read_to_end(&mut buf).ok()?; + let cgroup_path = buf + .split(|&c| c == b'\n') + .filter_map(|line| { + let mut fields = line.splitn(3, |&c| c == b':'); + // expect cgroupv2 which has an empty 2nd field + if fields.nth(1) != Some(b"") { + return None; + } + let path = fields.last()?; + // skip leading slash + Some(path[1..].to_owned()) + }) + .next()?; + let cgroup_path = PathBuf::from(OsString::from_vec(cgroup_path)); + + let mut path = PathBuf::with_capacity(128); + let mut read_buf = String::with_capacity(20); + + let cgroup_mount = "/sys/fs/cgroup"; + + path.push(cgroup_mount); + path.push(&cgroup_path); + + path.push("cgroup.controllers"); + + // skip if we're not looking at cgroup2 + if matches!(try_exists(&path), Err(_) | Ok(false)) { + return usize::MAX; + }; + + path.pop(); + + while path.starts_with(cgroup_mount) { + path.push("cpu.max"); + + read_buf.clear(); + + if File::open(&path).and_then(|mut f| f.read_to_string(&mut read_buf)).is_ok() { + let raw_quota = read_buf.lines().next()?; + let mut raw_quota = raw_quota.split(' '); + let limit = raw_quota.next()?; + let period = raw_quota.next()?; + match (limit.parse::<usize>(), period.parse::<usize>()) { + (Ok(limit), Ok(period)) => { + quota = quota.min(limit / period); + } + _ => {} + } + } + + path.pop(); // pop filename + path.pop(); // pop dir + } + }; + + quota +} + #[cfg(all( not(target_os = "linux"), not(target_os = "freebsd"), diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index c7b6290693e..9b61b2476d5 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -5,9 +5,10 @@ #![unstable(issue = "none", feature = "windows_c")] use crate::mem; -use crate::os::raw::NonZero_c_ulong; use crate::os::raw::{c_char, c_int, c_long, c_longlong, c_uint, c_ulong, c_ushort}; +use crate::os::windows::io::{BorrowedHandle, HandleOrInvalid, HandleOrNull}; use crate::ptr; +use core::ffi::NonZero_c_ulong; use libc::{c_void, size_t, wchar_t}; @@ -886,7 +887,7 @@ extern "system" { lpParameter: LPVOID, dwCreationFlags: DWORD, lpThreadId: LPDWORD, - ) -> HANDLE; + ) -> HandleOrNull; pub fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD; pub fn SwitchToThread() -> BOOL; pub fn Sleep(dwMilliseconds: DWORD); @@ -950,14 +951,14 @@ extern "system" { dwOptions: DWORD, ) -> BOOL; pub fn ReadFile( - hFile: HANDLE, + hFile: BorrowedHandle<'_>, lpBuffer: LPVOID, nNumberOfBytesToRead: DWORD, lpNumberOfBytesRead: LPDWORD, lpOverlapped: LPOVERLAPPED, ) -> BOOL; pub fn WriteFile( - hFile: HANDLE, + hFile: BorrowedHandle<'_>, lpBuffer: LPVOID, nNumberOfBytesToWrite: DWORD, lpNumberOfBytesWritten: LPDWORD, @@ -981,7 +982,7 @@ extern "system" { dwCreationDisposition: DWORD, dwFlagsAndAttributes: DWORD, hTemplateFile: HANDLE, - ) -> HANDLE; + ) -> HandleOrInvalid; pub fn FindFirstFileW(fileName: LPCWSTR, findFileData: LPWIN32_FIND_DATAW) -> HANDLE; pub fn FindNextFileW(findFile: HANDLE, findFileData: LPWIN32_FIND_DATAW) -> BOOL; diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index cb83ee2469a..d6c40a15329 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -1,5 +1,6 @@ use crate::os::windows::prelude::*; +use crate::convert::TryInto; use crate::ffi::OsString; use crate::fmt; use crate::io::{self, Error, IoSlice, IoSliceMut, ReadBuf, SeekFrom}; @@ -294,10 +295,10 @@ impl File { ptr::null_mut(), ) }; - if handle == c::INVALID_HANDLE_VALUE { - Err(Error::last_os_error()) + if let Ok(handle) = handle.try_into() { + Ok(File { handle: Handle::from_inner(handle) }) } else { - unsafe { Ok(File { handle: Handle::from_raw_handle(handle) }) } + Err(Error::last_os_error()) } } diff --git a/library/std/src/sys/windows/handle.rs b/library/std/src/sys/windows/handle.rs index daab39bb00c..e5c9567957b 100644 --- a/library/std/src/sys/windows/handle.rs +++ b/library/std/src/sys/windows/handle.rs @@ -78,7 +78,7 @@ impl Handle { let len = cmp::min(buf.len(), <c::DWORD>::MAX as usize) as c::DWORD; let res = cvt(unsafe { c::ReadFile( - self.as_raw_handle(), + self.as_handle(), buf.as_mut_ptr() as c::LPVOID, len, &mut read, @@ -116,7 +116,7 @@ impl Handle { overlapped.Offset = offset as u32; overlapped.OffsetHigh = (offset >> 32) as u32; cvt(c::ReadFile( - self.as_raw_handle(), + self.as_handle(), buf.as_mut_ptr() as c::LPVOID, len, &mut read, @@ -135,7 +135,7 @@ impl Handle { let len = cmp::min(buf.remaining(), <c::DWORD>::MAX as usize) as c::DWORD; let res = cvt(unsafe { c::ReadFile( - self.as_raw_handle(), + self.as_handle(), buf.unfilled_mut().as_mut_ptr() as c::LPVOID, len, &mut read, @@ -171,7 +171,7 @@ impl Handle { let len = cmp::min(buf.len(), <c::DWORD>::MAX as usize) as c::DWORD; let mut amt = 0; let res = cvt(c::ReadFile( - self.as_raw_handle(), + self.as_handle(), buf.as_ptr() as c::LPVOID, len, &mut amt, @@ -225,7 +225,7 @@ impl Handle { let len = cmp::min(buf.len(), <c::DWORD>::MAX as usize) as c::DWORD; cvt(unsafe { c::WriteFile( - self.as_raw_handle(), + self.as_handle(), buf.as_ptr() as c::LPVOID, len, &mut amt, @@ -252,7 +252,7 @@ impl Handle { overlapped.Offset = offset as u32; overlapped.OffsetHigh = (offset >> 32) as u32; cvt(c::WriteFile( - self.as_raw_handle(), + self.as_handle(), buf.as_ptr() as c::LPVOID, len, &mut written, diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs index dc288176346..6097e628768 100644 --- a/library/std/src/sys/windows/mod.rs +++ b/library/std/src/sys/windows/mod.rs @@ -224,8 +224,14 @@ where } as usize; if k == n && c::GetLastError() == c::ERROR_INSUFFICIENT_BUFFER { n *= 2; - } else if k >= n { + } else if k > n { n = k; + } else if k == n { + // It is impossible to reach this point. + // On success, k is the returned string length excluding the null. + // On failure, k is the required buffer length including the null. + // Therefore k never equals n. + unreachable!(); } else { return Ok(f2(&buf[..k])); } diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs index aa6400aeefa..5de12313784 100644 --- a/library/std/src/sys/windows/net.rs +++ b/library/std/src/sys/windows/net.rs @@ -407,11 +407,11 @@ impl Socket { } pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { - net::setsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY, nodelay as c::BYTE) + net::setsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY, nodelay as c::BOOL) } pub fn nodelay(&self) -> io::Result<bool> { - let raw: c::BYTE = net::getsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY)?; + let raw: c::BOOL = net::getsockopt(self, c::IPPROTO_TCP, c::TCP_NODELAY)?; Ok(raw != 0) } diff --git a/library/std/src/sys/windows/os.rs b/library/std/src/sys/windows/os.rs index 5f8556c3bc3..450bceae000 100644 --- a/library/std/src/sys/windows/os.rs +++ b/library/std/src/sys/windows/os.rs @@ -64,7 +64,7 @@ pub fn error_string(mut errnum: i32) -> String { if res == 0 { // Sometimes FormatMessageW can fail e.g., system doesn't like langId, let fm_err = errno(); - return format!("OS Error {} (FormatMessageW() returned error {})", errnum, fm_err); + return format!("OS Error {errnum} (FormatMessageW() returned error {fm_err})"); } match String::from_utf16(&buf[..res]) { diff --git a/library/std/src/sys/windows/process/tests.rs b/library/std/src/sys/windows/process/tests.rs index a199bb8b567..96477fb19da 100644 --- a/library/std/src/sys/windows/process/tests.rs +++ b/library/std/src/sys/windows/process/tests.rs @@ -124,9 +124,7 @@ fn windows_env_unicode_case() { assert_eq!( env::var(key).ok(), value.map(|s| s.to_string_lossy().into_owned()), - "command environment mismatch: {} {}", - a, - b + "command environment mismatch: {a} {b}", ); } } diff --git a/library/std/src/sys/windows/thread.rs b/library/std/src/sys/windows/thread.rs index e4bba9255d2..2f469513eb4 100644 --- a/library/std/src/sys/windows/thread.rs +++ b/library/std/src/sys/windows/thread.rs @@ -1,11 +1,13 @@ +use crate::convert::TryInto; use crate::ffi::CStr; use crate::io; use crate::num::NonZeroUsize; -use crate::os::windows::io::{AsRawHandle, FromRawHandle}; +use crate::os::windows::io::AsRawHandle; use crate::ptr; use crate::sys::c; use crate::sys::handle::Handle; use crate::sys::stack_overflow; +use crate::sys_common::FromInner; use crate::time::Duration; use libc::c_void; @@ -28,25 +30,22 @@ impl Thread { // PTHREAD_STACK_MIN bytes big. Windows has no such lower limit, it's // just that below a certain threshold you can't do anything useful. // That threshold is application and architecture-specific, however. - // Round up to the next 64 kB because that's what the NT kernel does, - // might as well make it explicit. - let stack_size = (stack + 0xfffe) & (!0xfffe); let ret = c::CreateThread( ptr::null_mut(), - stack_size, + stack, thread_start, p as *mut _, c::STACK_SIZE_PARAM_IS_A_RESERVATION, ptr::null_mut(), ); - return if ret as usize == 0 { + return if let Ok(handle) = ret.try_into() { + Ok(Thread { handle: Handle::from_inner(handle) }) + } else { // The thread failed to start and as a result p was not consumed. Therefore, it is // safe to reconstruct the box so that it gets deallocated. drop(Box::from_raw(p)); Err(io::Error::last_os_error()) - } else { - Ok(Thread { handle: Handle::from_raw_handle(ret) }) }; extern "system" fn thread_start(main: *mut c_void) -> c::DWORD { diff --git a/library/std/src/sys/windows/thread_parker.rs b/library/std/src/sys/windows/thread_parker.rs index 5a8011a9588..5888ee8e34b 100644 --- a/library/std/src/sys/windows/thread_parker.rs +++ b/library/std/src/sys/windows/thread_parker.rs @@ -230,7 +230,7 @@ fn keyed_event_handle() -> c::HANDLE { 0, ) { c::STATUS_SUCCESS => {} - r => panic!("Unable to create keyed event handle: error {}", r), + r => panic!("Unable to create keyed event handle: error {r}"), } } match HANDLE.compare_exchange(INVALID, handle as usize, Relaxed, Relaxed) { diff --git a/library/std/src/sys_common/backtrace.rs b/library/std/src/sys_common/backtrace.rs index b0b55592f6f..31164afdc7b 100644 --- a/library/std/src/sys_common/backtrace.rs +++ b/library/std/src/sys_common/backtrace.rs @@ -174,7 +174,7 @@ pub fn output_filename( if let Some(cwd) = cwd { if let Ok(stripped) = file.strip_prefix(&cwd) { if let Some(s) = stripped.to_str() { - return write!(fmt, ".{}{}", path::MAIN_SEPARATOR, s); + return write!(fmt, ".{}{s}", path::MAIN_SEPARATOR); } } } diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index 70b29d4a92e..3b7cdd55a08 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -58,21 +58,36 @@ cfg_if::cfg_if! { // sockaddr and misc bindings //////////////////////////////////////////////////////////////////////////////// -pub fn setsockopt<T>(sock: &Socket, opt: c_int, val: c_int, payload: T) -> io::Result<()> { +pub fn setsockopt<T>( + sock: &Socket, + level: c_int, + option_name: c_int, + option_value: T, +) -> io::Result<()> { unsafe { - let payload = &payload as *const T as *const c_void; - cvt(c::setsockopt(sock.as_raw(), opt, val, payload, mem::size_of::<T>() as c::socklen_t))?; + cvt(c::setsockopt( + sock.as_raw(), + level, + option_name, + &option_value as *const T as *const _, + mem::size_of::<T>() as c::socklen_t, + ))?; Ok(()) } } -pub fn getsockopt<T: Copy>(sock: &Socket, opt: c_int, val: c_int) -> io::Result<T> { +pub fn getsockopt<T: Copy>(sock: &Socket, level: c_int, option_name: c_int) -> io::Result<T> { unsafe { - let mut slot: T = mem::zeroed(); - let mut len = mem::size_of::<T>() as c::socklen_t; - cvt(c::getsockopt(sock.as_raw(), opt, val, &mut slot as *mut _ as *mut _, &mut len))?; - assert_eq!(len as usize, mem::size_of::<T>()); - Ok(slot) + let mut option_value: T = mem::zeroed(); + let mut option_len = mem::size_of::<T>() as c::socklen_t; + cvt(c::getsockopt( + sock.as_raw(), + level, + option_name, + &mut option_value as *mut T as *mut _, + &mut option_len, + ))?; + Ok(option_value) } } diff --git a/library/std/src/sys_common/net/tests.rs b/library/std/src/sys_common/net/tests.rs index 7d45621e09a..ac75d9ebfc8 100644 --- a/library/std/src/sys_common/net/tests.rs +++ b/library/std/src/sys_common/net/tests.rs @@ -6,7 +6,7 @@ fn no_lookup_host_duplicates() { let mut addrs = HashMap::new(); let lh = match LookupHost::try_from(("localhost", 0)) { Ok(lh) => lh, - Err(e) => panic!("couldn't resolve `localhost': {}", e), + Err(e) => panic!("couldn't resolve `localhost': {e}"), }; for sa in lh { *addrs.entry(sa).or_insert(0) += 1; diff --git a/library/std/src/sys_common/thread_parker/generic.rs b/library/std/src/sys_common/thread_parker/generic.rs index d99e901bb5f..ffb61200e15 100644 --- a/library/std/src/sys_common/thread_parker/generic.rs +++ b/library/std/src/sys_common/thread_parker/generic.rs @@ -84,7 +84,7 @@ impl Parker { match self.state.swap(EMPTY, SeqCst) { NOTIFIED => {} // got a notification, hurray! PARKED => {} // no notification, alas - n => panic!("inconsistent park_timeout state: {}", n), + n => panic!("inconsistent park_timeout state: {n}"), } } diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs index 7a6e6246357..10ef6662115 100644 --- a/library/std/src/sys_common/wtf8.rs +++ b/library/std/src/sys_common/wtf8.rs @@ -830,7 +830,7 @@ pub unsafe fn slice_unchecked(s: &Wtf8, begin: usize, end: usize) -> &Wtf8 { #[inline(never)] pub fn slice_error_fail(s: &Wtf8, begin: usize, end: usize) -> ! { assert!(begin <= end); - panic!("index {} and/or {} in `{:?}` do not lie on character boundary", begin, end, s); + panic!("index {begin} and/or {end} in `{s:?}` do not lie on character boundary"); } /// Iterator for the code points of a WTF-8 string. diff --git a/library/std/src/sys_common/wtf8/tests.rs b/library/std/src/sys_common/wtf8/tests.rs index 1bafbaa6939..931996791fb 100644 --- a/library/std/src/sys_common/wtf8/tests.rs +++ b/library/std/src/sys_common/wtf8/tests.rs @@ -266,7 +266,7 @@ fn wtf8buf_extend() { fn wtf8buf_show() { let mut string = Wtf8Buf::from_str("a\té \u{7f}💩\r"); string.push(CodePoint::from_u32(0xD800).unwrap()); - assert_eq!(format!("{:?}", string), "\"a\\té \\u{7f}\u{1f4a9}\\r\\u{d800}\""); + assert_eq!(format!("{string:?}"), "\"a\\té \\u{7f}\u{1f4a9}\\r\\u{d800}\""); } #[test] @@ -278,7 +278,7 @@ fn wtf8buf_as_slice() { fn wtf8buf_show_str() { let text = "a\té 💩\r"; let string = Wtf8Buf::from_str(text); - assert_eq!(format!("{:?}", text), format!("{:?}", string)); + assert_eq!(format!("{text:?}"), format!("{string:?}")); } #[test] diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 1be3ed757ba..a100444f049 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -8,6 +8,7 @@ mod tests; #[cfg(test)] mod dynamic_tests; +use crate::cell::{Cell, RefCell}; use crate::error::Error; use crate::fmt; @@ -108,7 +109,7 @@ pub struct LocalKey<T: 'static> { // trivially devirtualizable by LLVM because the value of `inner` never // changes and the constant should be readonly within a crate. This mainly // only runs into problems when TLS statics are exported across crates. - inner: unsafe fn() -> Option<&'static T>, + inner: unsafe fn(Option<&mut Option<T>>) -> Option<&'static T>, } #[stable(feature = "std_debug", since = "1.16.0")] @@ -177,8 +178,10 @@ macro_rules! thread_local { macro_rules! __thread_local_inner { // used to generate the `LocalKey` value for const-initialized thread locals (@key $t:ty, const $init:expr) => {{ - #[cfg_attr(not(windows), inline)] // see comments below - unsafe fn __getit() -> $crate::option::Option<&'static $t> { + #[cfg_attr(not(windows), inline(always))] // see comments below + unsafe fn __getit( + _init: $crate::option::Option<&mut $crate::option::Option<$t>>, + ) -> $crate::option::Option<&'static $t> { const INIT_EXPR: $t = $init; // wasm without atomics maps directly to `static mut`, and dtors @@ -260,7 +263,18 @@ macro_rules! __thread_local_inner { static __KEY: $crate::thread::__OsLocalKeyInner<$t> = $crate::thread::__OsLocalKeyInner::new(); #[allow(unused_unsafe)] - unsafe { __KEY.get(__init) } + unsafe { + __KEY.get(move || { + if let $crate::option::Option::Some(init) = _init { + if let $crate::option::Option::Some(value) = init.take() { + return value; + } else if $crate::cfg!(debug_assertions) { + unreachable!("missing initial value"); + } + } + __init() + }) + } } } @@ -297,8 +311,10 @@ macro_rules! __thread_local_inner { // gets the pessimistic path for now where it's never inlined. // // The issue of "should enable on Windows sometimes" is #84933 - #[cfg_attr(not(windows), inline)] - unsafe fn __getit() -> $crate::option::Option<&'static $t> { + #[cfg_attr(not(windows), inline(always))] + unsafe fn __getit( + init: $crate::option::Option<&mut $crate::option::Option<$t>>, + ) -> $crate::option::Option<&'static $t> { #[cfg(all(target_family = "wasm", not(target_feature = "atomics")))] static __KEY: $crate::thread::__StaticLocalKeyInner<$t> = $crate::thread::__StaticLocalKeyInner::new(); @@ -322,7 +338,18 @@ macro_rules! __thread_local_inner { // raise warning for missing/extraneous unsafe blocks anymore. // See https://github.com/rust-lang/rust/issues/74838. #[allow(unused_unsafe)] - unsafe { __KEY.get(__init) } + unsafe { + __KEY.get(move || { + if let $crate::option::Option::Some(init) = init { + if let $crate::option::Option::Some(value) = init.take() { + return value; + } else if $crate::cfg!(debug_assertions) { + unreachable!("missing default value"); + } + } + __init() + }) + } } unsafe { @@ -367,7 +394,9 @@ impl<T: 'static> LocalKey<T> { issue = "none" )] #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")] - pub const unsafe fn new(inner: unsafe fn() -> Option<&'static T>) -> LocalKey<T> { + pub const unsafe fn new( + inner: unsafe fn(Option<&mut Option<T>>) -> Option<&'static T>, + ) -> LocalKey<T> { LocalKey { inner } } @@ -409,10 +438,342 @@ impl<T: 'static> LocalKey<T> { F: FnOnce(&T) -> R, { unsafe { - let thread_local = (self.inner)().ok_or(AccessError)?; + let thread_local = (self.inner)(None).ok_or(AccessError)?; Ok(f(thread_local)) } } + + /// Acquires a reference to the value in this TLS key, initializing it with + /// `init` if it wasn't already initialized on this thread. + /// + /// If `init` was used to initialize the thread local variable, `None` is + /// passed as the first argument to `f`. If it was already initialized, + /// `Some(init)` is passed to `f`. + /// + /// # Panics + /// + /// This function will panic if the key currently has its destructor + /// running, and it **may** panic if the destructor has previously been run + /// for this thread. + fn initialize_with<F, R>(&'static self, init: T, f: F) -> R + where + F: FnOnce(Option<T>, &T) -> R, + { + unsafe { + let mut init = Some(init); + let reference = (self.inner)(Some(&mut init)).expect( + "cannot access a Thread Local Storage value \ + during or after destruction", + ); + f(init, reference) + } + } +} + +impl<T: 'static> LocalKey<Cell<T>> { + /// Sets or initializes the contained value. + /// + /// Unlike the other methods, this will *not* run the lazy initializer of + /// the thread local. Instead, it will be directly initialized with the + /// given value if it wasn't initialized yet. + /// + /// # Panics + /// + /// Panics if the key currently has its destructor running, + /// and it **may** panic if the destructor has previously been run for this thread. + /// + /// # Examples + /// + /// ``` + /// #![feature(local_key_cell_methods)] + /// use std::cell::Cell; + /// + /// thread_local! { + /// static X: Cell<i32> = panic!("!"); + /// } + /// + /// // Calling X.get() here would result in a panic. + /// + /// X.set(123); // But X.set() is fine, as it skips the initializer above. + /// + /// assert_eq!(X.get(), 123); + /// ``` + #[unstable(feature = "local_key_cell_methods", issue = "92122")] + pub fn set(&'static self, value: T) { + self.initialize_with(Cell::new(value), |value, cell| { + if let Some(value) = value { + // The cell was already initialized, so `value` wasn't used to + // initialize it. So we overwrite the current value with the + // new one instead. + cell.set(value.into_inner()); + } + }); + } + + /// Returns a copy of the contained value. + /// + /// This will lazily initialize the value if this thread has not referenced + /// this key yet. + /// + /// # Panics + /// + /// Panics if the key currently has its destructor running, + /// and it **may** panic if the destructor has previously been run for this thread. + /// + /// # Examples + /// + /// ``` + /// #![feature(local_key_cell_methods)] + /// use std::cell::Cell; + /// + /// thread_local! { + /// static X: Cell<i32> = Cell::new(1); + /// } + /// + /// assert_eq!(X.get(), 1); + /// ``` + #[unstable(feature = "local_key_cell_methods", issue = "92122")] + pub fn get(&'static self) -> T + where + T: Copy, + { + self.with(|cell| cell.get()) + } + + /// Takes the contained value, leaving `Default::default()` in its place. + /// + /// This will lazily initialize the value if this thread has not referenced + /// this key yet. + /// + /// # Panics + /// + /// Panics if the key currently has its destructor running, + /// and it **may** panic if the destructor has previously been run for this thread. + /// + /// # Examples + /// + /// ``` + /// #![feature(local_key_cell_methods)] + /// use std::cell::Cell; + /// + /// thread_local! { + /// static X: Cell<Option<i32>> = Cell::new(Some(1)); + /// } + /// + /// assert_eq!(X.take(), Some(1)); + /// assert_eq!(X.take(), None); + /// ``` + #[unstable(feature = "local_key_cell_methods", issue = "92122")] + pub fn take(&'static self) -> T + where + T: Default, + { + self.with(|cell| cell.take()) + } + + /// Replaces the contained value, returning the old value. + /// + /// This will lazily initialize the value if this thread has not referenced + /// this key yet. + /// + /// # Panics + /// + /// Panics if the key currently has its destructor running, + /// and it **may** panic if the destructor has previously been run for this thread. + /// + /// # Examples + /// + /// ``` + /// #![feature(local_key_cell_methods)] + /// use std::cell::Cell; + /// + /// thread_local! { + /// static X: Cell<i32> = Cell::new(1); + /// } + /// + /// assert_eq!(X.replace(2), 1); + /// assert_eq!(X.replace(3), 2); + /// ``` + #[unstable(feature = "local_key_cell_methods", issue = "92122")] + pub fn replace(&'static self, value: T) -> T { + self.with(|cell| cell.replace(value)) + } +} + +impl<T: 'static> LocalKey<RefCell<T>> { + /// Acquires a reference to the contained value. + /// + /// This will lazily initialize the value if this thread has not referenced + /// this key yet. + /// + /// # Panics + /// + /// Panics if the value is currently mutably borrowed. + /// + /// Panics if the key currently has its destructor running, + /// and it **may** panic if the destructor has previously been run for this thread. + /// + /// # Example + /// + /// ``` + /// #![feature(local_key_cell_methods)] + /// use std::cell::RefCell; + /// + /// thread_local! { + /// static X: RefCell<Vec<i32>> = RefCell::new(Vec::new()); + /// } + /// + /// X.with_borrow(|v| assert!(v.is_empty())); + /// ``` + #[unstable(feature = "local_key_cell_methods", issue = "92122")] + pub fn with_borrow<F, R>(&'static self, f: F) -> R + where + F: FnOnce(&T) -> R, + { + self.with(|cell| f(&cell.borrow())) + } + + /// Acquires a mutable reference to the contained value. + /// + /// This will lazily initialize the value if this thread has not referenced + /// this key yet. + /// + /// # Panics + /// + /// Panics if the value is currently borrowed. + /// + /// Panics if the key currently has its destructor running, + /// and it **may** panic if the destructor has previously been run for this thread. + /// + /// # Example + /// + /// ``` + /// #![feature(local_key_cell_methods)] + /// use std::cell::RefCell; + /// + /// thread_local! { + /// static X: RefCell<Vec<i32>> = RefCell::new(Vec::new()); + /// } + /// + /// X.with_borrow_mut(|v| v.push(1)); + /// + /// X.with_borrow(|v| assert_eq!(*v, vec![1])); + /// ``` + #[unstable(feature = "local_key_cell_methods", issue = "92122")] + pub fn with_borrow_mut<F, R>(&'static self, f: F) -> R + where + F: FnOnce(&mut T) -> R, + { + self.with(|cell| f(&mut cell.borrow_mut())) + } + + /// Sets or initializes the contained value. + /// + /// Unlike the other methods, this will *not* run the lazy initializer of + /// the thread local. Instead, it will be directly initialized with the + /// given value if it wasn't initialized yet. + /// + /// # Panics + /// + /// Panics if the value is currently borrowed. + /// + /// Panics if the key currently has its destructor running, + /// and it **may** panic if the destructor has previously been run for this thread. + /// + /// # Examples + /// + /// ``` + /// #![feature(local_key_cell_methods)] + /// use std::cell::RefCell; + /// + /// thread_local! { + /// static X: RefCell<Vec<i32>> = panic!("!"); + /// } + /// + /// // Calling X.with() here would result in a panic. + /// + /// X.set(vec![1, 2, 3]); // But X.set() is fine, as it skips the initializer above. + /// + /// X.with_borrow(|v| assert_eq!(*v, vec![1, 2, 3])); + /// ``` + #[unstable(feature = "local_key_cell_methods", issue = "92122")] + pub fn set(&'static self, value: T) { + self.initialize_with(RefCell::new(value), |value, cell| { + if let Some(value) = value { + // The cell was already initialized, so `value` wasn't used to + // initialize it. So we overwrite the current value with the + // new one instead. + *cell.borrow_mut() = value.into_inner(); + } + }); + } + + /// Takes the contained value, leaving `Default::default()` in its place. + /// + /// This will lazily initialize the value if this thread has not referenced + /// this key yet. + /// + /// # Panics + /// + /// Panics if the value is currently borrowed. + /// + /// Panics if the key currently has its destructor running, + /// and it **may** panic if the destructor has previously been run for this thread. + /// + /// # Examples + /// + /// ``` + /// #![feature(local_key_cell_methods)] + /// use std::cell::RefCell; + /// + /// thread_local! { + /// static X: RefCell<Vec<i32>> = RefCell::new(Vec::new()); + /// } + /// + /// X.with_borrow_mut(|v| v.push(1)); + /// + /// let a = X.take(); + /// + /// assert_eq!(a, vec![1]); + /// + /// X.with_borrow(|v| assert!(v.is_empty())); + /// ``` + #[unstable(feature = "local_key_cell_methods", issue = "92122")] + pub fn take(&'static self) -> T + where + T: Default, + { + self.with(|cell| cell.take()) + } + + /// Replaces the contained value, returning the old value. + /// + /// # Panics + /// + /// Panics if the value is currently borrowed. + /// + /// Panics if the key currently has its destructor running, + /// and it **may** panic if the destructor has previously been run for this thread. + /// + /// # Examples + /// + /// ``` + /// #![feature(local_key_cell_methods)] + /// use std::cell::RefCell; + /// + /// thread_local! { + /// static X: RefCell<Vec<i32>> = RefCell::new(Vec::new()); + /// } + /// + /// let prev = X.replace(vec![1, 2, 3]); + /// assert!(prev.is_empty()); + /// + /// X.with_borrow(|v| assert_eq!(*v, vec![1, 2, 3])); + /// ``` + #[unstable(feature = "local_key_cell_methods", issue = "92122")] + pub fn replace(&'static self, value: T) -> T { + self.with(|cell| cell.replace(value)) + } } mod lazy { @@ -518,7 +879,7 @@ pub mod statik { Key { inner: LazyKeyInner::new() } } - pub unsafe fn get(&self, init: fn() -> T) -> Option<&'static T> { + pub unsafe fn get(&self, init: impl FnOnce() -> T) -> Option<&'static T> { // SAFETY: The caller must ensure no reference is ever handed out to // the inner cell nor mutable reference to the Option<T> inside said // cell. This make it safe to hand a reference, though the lifetime @@ -707,7 +1068,7 @@ pub mod os { /// It is a requirement for the caller to ensure that no mutable /// reference is active when this method is called. - pub unsafe fn get(&'static self, init: fn() -> T) -> Option<&'static T> { + pub unsafe fn get(&'static self, init: impl FnOnce() -> T) -> Option<&'static T> { // SAFETY: See the documentation for this method. let ptr = unsafe { self.os.get() as *mut Value<T> }; if ptr as usize > 1 { @@ -725,7 +1086,7 @@ pub mod os { // `try_initialize` is only called once per os thread local variable, // except in corner cases where thread_local dtors reference other // thread_local's, or it is being recursively initialized. - unsafe fn try_initialize(&'static self, init: fn() -> T) -> Option<&'static T> { + unsafe fn try_initialize(&'static self, init: impl FnOnce() -> T) -> Option<&'static T> { // SAFETY: No mutable references are ever handed out meaning getting // the value is ok. let ptr = unsafe { self.os.get() as *mut Value<T> }; diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index f8d790c3785..ae292caaed9 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -613,7 +613,7 @@ impl Builder { /// /// let receiver = thread::spawn(move || { /// let value = rx.recv().expect("Unable to receive from channel"); -/// println!("{}", value); +/// println!("{value}"); /// }); /// /// sender.join().expect("The sender thread has panicked"); @@ -633,7 +633,7 @@ impl Builder { /// }); /// /// let result = computation.join().unwrap(); -/// println!("{}", result); +/// println!("{result}"); /// ``` /// /// [`channels`]: crate::sync::mpsc @@ -979,7 +979,7 @@ pub fn park_timeout_ms(ms: u32) { /// if elapsed >= timeout { /// break; /// } -/// println!("restarting park_timeout after {:?}", elapsed); +/// println!("restarting park_timeout after {elapsed:?}"); /// timeout_remaining = timeout - elapsed; /// } /// ``` @@ -1287,12 +1287,31 @@ unsafe impl<'scope, T: Sync> Sync for Packet<'scope, T> {} impl<'scope, T> Drop for Packet<'scope, T> { fn drop(&mut self) { + // If this packet was for a thread that ran in a scope, the thread + // panicked, and nobody consumed the panic payload, we make sure + // the scope function will panic. + let unhandled_panic = matches!(self.result.get_mut(), Some(Err(_))); + // Drop the result without causing unwinding. + // This is only relevant for threads that aren't join()ed, as + // join() will take the `result` and set it to None, such that + // there is nothing left to drop here. + // If this panics, we should handle that, because we're outside the + // outermost `catch_unwind` of our thread. + // We just abort in that case, since there's nothing else we can do. + // (And even if we tried to handle it somehow, we'd also need to handle + // the case where the panic payload we get out of it also panics on + // drop, and so on. See issue #86027.) + if let Err(_) = panic::catch_unwind(panic::AssertUnwindSafe(|| { + *self.result.get_mut() = None; + })) { + rtabort!("thread result panicked on drop"); + } // Book-keeping so the scope knows when it's done. if let Some(scope) = self.scope { - // If this packet was for a thread that ran in a scope, the thread - // panicked, and nobody consumed the panic payload, we make sure - // the scope function will panic. - let unhandled_panic = matches!(self.result.get_mut(), Some(Err(_))); + // Now that there will be no more user code running on this thread + // that can use 'scope, mark the thread as 'finished'. + // It's important we only do this after the `result` has been dropped, + // since dropping it might still use things it borrowed from 'scope. scope.decrement_num_running_threads(unhandled_panic); } } @@ -1443,13 +1462,18 @@ impl<T> JoinHandle<T> { self.0.join() } - /// Checks if the associated thread is still running its main function. + /// Checks if the associated thread has finished running its main function. /// - /// This might return `false` for a brief moment after the thread's main + /// This might return `true` for a brief moment after the thread's main /// function has returned, but before the thread itself has stopped running. + /// However, once this returns `true`, [`join`][Self::join] can be expected + /// to return quickly, without blocking for any significant amount of time. + /// + /// This function does not block. To block while waiting on the thread to finish, + /// use [`join`][Self::join]. #[unstable(feature = "thread_is_running", issue = "90470")] - pub fn is_running(&self) -> bool { - Arc::strong_count(&self.0.packet) > 1 + pub fn is_finished(&self) -> bool { + Arc::strong_count(&self.0.packet) == 1 } } @@ -1482,7 +1506,7 @@ fn _assert_sync_and_send() { /// /// Parallelism is a resource. A given machine provides a certain capacity for /// parallelism, i.e., a bound on the number of computations it can perform -/// simultaneously. This number often corresponds to the amount of CPUs or +/// simultaneously. This number often corresponds to the amount of CPUs a /// computer has, but it may diverge in various cases. /// /// Host environments such as VMs or container orchestrators may want to @@ -1524,7 +1548,10 @@ fn _assert_sync_and_send() { /// /// On Linux: /// - It may overcount the amount of parallelism available when limited by a -/// process-wide affinity mask, or when affected by cgroup limits. +/// process-wide affinity mask or cgroup quotas and cgroup2 fs or `sched_getaffinity()` can't be +/// queried, e.g. due to sandboxing. +/// - It may undercount the amount of parallelism if the current thread's affinity mask +/// does not reflect the process' cpuset, e.g. due to pinned threads. /// /// On all targets: /// - It may overcount the amount of parallelism available when running in a VM diff --git a/library/std/src/thread/scoped.rs b/library/std/src/thread/scoped.rs index 9dd7c15fc59..07e113f3b62 100644 --- a/library/std/src/thread/scoped.rs +++ b/library/std/src/thread/scoped.rs @@ -9,23 +9,24 @@ use crate::sync::Arc; /// A scope to spawn scoped threads in. /// /// See [`scope`] for details. -pub struct Scope<'env> { +pub struct Scope<'scope, 'env: 'scope> { data: ScopeData, - /// Invariance over 'env, to make sure 'env cannot shrink, + /// Invariance over 'scope, to make sure 'scope cannot shrink, /// which is necessary for soundness. /// /// Without invariance, this would compile fine but be unsound: /// - /// ```compile_fail + /// ```compile_fail,E0373 /// #![feature(scoped_threads)] /// /// std::thread::scope(|s| { - /// s.spawn(|s| { + /// s.spawn(|| { /// let a = String::from("abcd"); - /// s.spawn(|_| println!("{:?}", a)); // might run after `a` is dropped + /// s.spawn(|| println!("{a:?}")); // might run after `a` is dropped /// }); /// }); /// ``` + scope: PhantomData<&'scope mut &'scope ()>, env: PhantomData<&'env mut &'env ()>, } @@ -88,12 +89,12 @@ impl ScopeData { /// let mut x = 0; /// /// thread::scope(|s| { -/// s.spawn(|_| { +/// s.spawn(|| { /// println!("hello from the first scoped thread"); /// // We can borrow `a` here. /// dbg!(&a); /// }); -/// s.spawn(|_| { +/// s.spawn(|| { /// println!("hello from the second scoped thread"); /// // We can even mutably borrow `x` here, /// // because no other threads are using it. @@ -106,10 +107,28 @@ impl ScopeData { /// a.push(4); /// assert_eq!(x, a.len()); /// ``` +/// +/// # Lifetimes +/// +/// Scoped threads involve two lifetimes: `'scope` and `'env`. +/// +/// The `'scope` lifetime represents the lifetime of the scope itself. +/// That is: the time during which new scoped threads may be spawned, +/// and also the time during which they might still be running. +/// Once this lifetime ends, all scoped threads are joined. +/// This lifetime starts within the `scope` function, before `f` (the argument to `scope`) starts. +/// It ends after `f` returns and all scoped threads have been joined, but before `scope` returns. +/// +/// The `'env` lifetime represents the lifetime of whatever is borrowed by the scoped threads. +/// This lifetime must outlast the call to `scope`, and thus cannot be smaller than `'scope`. +/// It can be as small as the call to `scope`, meaning that anything that outlives this call, +/// such as local variables defined right before the scope, can be borrowed by the scoped threads. +/// +/// The `'env: 'scope` bound is part of the definition of the `Scope` type. #[track_caller] pub fn scope<'env, F, T>(f: F) -> T where - F: FnOnce(&Scope<'env>) -> T, + F: for<'scope> FnOnce(&'scope Scope<'scope, 'env>) -> T, { let scope = Scope { data: ScopeData { @@ -118,6 +137,7 @@ where a_thread_panicked: AtomicBool::new(false), }, env: PhantomData, + scope: PhantomData, }; // Run `f`, but catch panics so we can make sure to wait for all the threads to join. @@ -138,7 +158,7 @@ where } } -impl<'env> Scope<'env> { +impl<'scope, 'env> Scope<'scope, 'env> { /// Spawns a new thread within a scope, returning a [`ScopedJoinHandle`] for it. /// /// Unlike non-scoped threads, threads spawned with this function may @@ -163,10 +183,10 @@ impl<'env> Scope<'env> { /// to recover from such errors. /// /// [`join`]: ScopedJoinHandle::join - pub fn spawn<'scope, F, T>(&'scope self, f: F) -> ScopedJoinHandle<'scope, T> + pub fn spawn<F, T>(&'scope self, f: F) -> ScopedJoinHandle<'scope, T> where - F: FnOnce(&Scope<'env>) -> T + Send + 'env, - T: Send + 'env, + F: FnOnce() -> T + Send + 'scope, + T: Send + 'scope, { Builder::new().spawn_scoped(self, f).expect("failed to spawn thread") } @@ -196,7 +216,7 @@ impl Builder { /// thread::scope(|s| { /// thread::Builder::new() /// .name("first".to_string()) - /// .spawn_scoped(s, |_| + /// .spawn_scoped(s, || /// { /// println!("hello from the {:?} scoped thread", thread::current().name()); /// // We can borrow `a` here. @@ -205,7 +225,7 @@ impl Builder { /// .unwrap(); /// thread::Builder::new() /// .name("second".to_string()) - /// .spawn_scoped(s, |_| + /// .spawn_scoped(s, || /// { /// println!("hello from the {:?} scoped thread", thread::current().name()); /// // We can even mutably borrow `x` here, @@ -222,14 +242,14 @@ impl Builder { /// ``` pub fn spawn_scoped<'scope, 'env, F, T>( self, - scope: &'scope Scope<'env>, + scope: &'scope Scope<'scope, 'env>, f: F, ) -> io::Result<ScopedJoinHandle<'scope, T>> where - F: FnOnce(&Scope<'env>) -> T + Send + 'env, - T: Send + 'env, + F: FnOnce() -> T + Send + 'scope, + T: Send + 'scope, { - Ok(ScopedJoinHandle(unsafe { self.spawn_unchecked_(|| f(scope), Some(&scope.data)) }?)) + Ok(ScopedJoinHandle(unsafe { self.spawn_unchecked_(f, Some(&scope.data)) }?)) } } @@ -240,12 +260,11 @@ impl<'scope, T> ScopedJoinHandle<'scope, T> { /// /// ``` /// #![feature(scoped_threads)] - /// #![feature(thread_is_running)] /// /// use std::thread; /// /// thread::scope(|s| { - /// let t = s.spawn(|_| { + /// let t = s.spawn(|| { /// println!("hello"); /// }); /// println!("thread id: {:?}", t.thread().id()); @@ -274,12 +293,11 @@ impl<'scope, T> ScopedJoinHandle<'scope, T> { /// /// ``` /// #![feature(scoped_threads)] - /// #![feature(thread_is_running)] /// /// use std::thread; /// /// thread::scope(|s| { - /// let t = s.spawn(|_| { + /// let t = s.spawn(|| { /// panic!("oh no"); /// }); /// assert!(t.join().is_err()); @@ -289,17 +307,22 @@ impl<'scope, T> ScopedJoinHandle<'scope, T> { self.0.join() } - /// Checks if the associated thread is still running its main function. + /// Checks if the associated thread has finished running its main function. /// - /// This might return `false` for a brief moment after the thread's main + /// This might return `true` for a brief moment after the thread's main /// function has returned, but before the thread itself has stopped running. + /// However, once this returns `true`, [`join`][Self::join] can be expected + /// to return quickly, without blocking for any significant amount of time. + /// + /// This function does not block. To block while waiting on the thread to finish, + /// use [`join`][Self::join]. #[unstable(feature = "thread_is_running", issue = "90470")] - pub fn is_running(&self) -> bool { - Arc::strong_count(&self.0.packet) > 1 + pub fn is_finished(&self) -> bool { + Arc::strong_count(&self.0.packet) == 1 } } -impl<'env> fmt::Debug for Scope<'env> { +impl fmt::Debug for Scope<'_, '_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Scope") .field("num_running_threads", &self.data.num_running_threads.load(Ordering::Relaxed)) diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs index 4f2c81731a3..7386fe1c442 100644 --- a/library/std/src/thread/tests.rs +++ b/library/std/src/thread/tests.rs @@ -4,10 +4,11 @@ use crate::mem; use crate::panic::panic_any; use crate::result; use crate::sync::{ + atomic::{AtomicBool, Ordering}, mpsc::{channel, Sender}, Arc, Barrier, }; -use crate::thread::{self, ThreadId}; +use crate::thread::{self, Scope, ThreadId}; use crate::time::Duration; use crate::time::Instant; @@ -52,7 +53,7 @@ fn test_run_basic() { } #[test] -fn test_is_running() { +fn test_is_finished() { let b = Arc::new(Barrier::new(2)); let t = thread::spawn({ let b = b.clone(); @@ -63,14 +64,14 @@ fn test_is_running() { }); // Thread is definitely running here, since it's still waiting for the barrier. - assert_eq!(t.is_running(), true); + assert_eq!(t.is_finished(), false); // Unblock the barrier. b.wait(); - // Now check that t.is_running() becomes false within a reasonable time. + // Now check that t.is_finished() becomes true within a reasonable time. let start = Instant::now(); - while t.is_running() { + while !t.is_finished() { assert!(start.elapsed() < Duration::from_secs(2)); thread::sleep(Duration::from_millis(15)); } @@ -293,5 +294,25 @@ fn test_thread_id_not_equal() { assert!(thread::current().id() != spawned_id); } -// NOTE: the corresponding test for stderr is in ui/thread-stderr, due -// to the test harness apparently interfering with stderr configuration. +#[test] +fn test_scoped_threads_drop_result_before_join() { + let actually_finished = &AtomicBool::new(false); + struct X<'scope, 'env>(&'scope Scope<'scope, 'env>, &'env AtomicBool); + impl Drop for X<'_, '_> { + fn drop(&mut self) { + thread::sleep(Duration::from_millis(20)); + let actually_finished = self.1; + self.0.spawn(move || { + thread::sleep(Duration::from_millis(20)); + actually_finished.store(true, Ordering::Relaxed); + }); + } + } + thread::scope(|s| { + s.spawn(move || { + thread::sleep(Duration::from_millis(20)); + X(s, actually_finished) + }); + }); + assert!(actually_finished.load(Ordering::Relaxed)); +} diff --git a/library/std/src/time.rs b/library/std/src/time.rs index df8a726e64e..2f8eb557b4f 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -191,7 +191,7 @@ pub struct Instant(time::Instant); /// } /// Err(e) => { /// // an error occurred! -/// println!("Error: {:?}", e); +/// println!("Error: {e:?}"); /// } /// } /// } @@ -513,7 +513,7 @@ impl SystemTime { /// let new_sys_time = SystemTime::now(); /// let difference = new_sys_time.duration_since(sys_time) /// .expect("Clock may have gone backwards"); - /// println!("{:?}", difference); + /// println!("{difference:?}"); /// ``` #[stable(feature = "time2", since = "1.8.0")] pub fn duration_since(&self, earlier: SystemTime) -> Result<Duration, SystemTimeError> { diff --git a/library/std/src/time/tests.rs b/library/std/src/time/tests.rs index d1a69ff8697..d710a574465 100644 --- a/library/std/src/time/tests.rs +++ b/library/std/src/time/tests.rs @@ -55,10 +55,10 @@ fn instant_elapsed() { fn instant_math() { let a = Instant::now(); let b = Instant::now(); - println!("a: {:?}", a); - println!("b: {:?}", b); + println!("a: {a:?}"); + println!("b: {b:?}"); let dur = b.duration_since(a); - println!("dur: {:?}", dur); + println!("dur: {dur:?}"); assert_almost_eq!(b - dur, a); assert_almost_eq!(a + dur, b); |
