diff options
Diffstat (limited to 'library/std/src')
95 files changed, 1940 insertions, 666 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 c0524352193..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")] @@ -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")] @@ -470,7 +470,7 @@ impl<K, V, S> HashMap<K, V, S> { /// ]); /// /// for (key, val) in map.iter() { - /// println!("key: {} val: {}", key, val); + /// println!("key: {key} val: {val}"); /// } /// ``` #[rustc_lint_query_instability] @@ -500,7 +500,7 @@ impl<K, V, S> HashMap<K, V, S> { /// } /// /// for (key, val) in &map { - /// println!("key: {} val: {}", key, val); + /// println!("key: {key} val: {val}"); /// } /// ``` #[rustc_lint_query_instability] @@ -621,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 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 2eb4cacabb8..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,7 +181,7 @@ impl<T, S> HashSet<T, S> { /// /// // Will print in an arbitrary order. /// for x in set.iter() { - /// println!("{}", x); + /// println!("{x}"); /// } /// ``` #[inline] @@ -244,7 +244,7 @@ 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()); @@ -300,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 @@ -525,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(); @@ -555,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(); @@ -586,7 +586,7 @@ where /// /// // Print 2, 3 in arbitrary order. /// for x in a.intersection(&b) { - /// println!("{}", x); + /// println!("{x}"); /// } /// /// let intersection: HashSet<_> = a.intersection(&b).collect(); @@ -615,7 +615,7 @@ 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(); @@ -1451,7 +1451,7 @@ impl<T, S> IntoIterator for HashSet<T, S> { /// /// // Will print in an arbitrary order. /// for x in &v { - /// println!("{}", x); + /// println!("{x}"); /// } /// ``` #[inline] 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 1678367290e..b833d0e2ca5 100644 --- a/library/std/src/ffi/c_str.rs +++ b/library/std/src/ffi/c_str.rs @@ -1120,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(()) } @@ -1134,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") diff --git a/library/std/src/ffi/c_str/tests.rs b/library/std/src/ffi/c_str/tests.rs index 00ba5460821..8d603229315 100644 --- a/library/std/src/ffi/c_str/tests.rs +++ b/library/std/src/ffi/c_str/tests.rs @@ -35,7 +35,7 @@ fn build_with_zero2() { #[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/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/cursor.rs b/library/std/src/io/cursor.rs index fc19704bece..57f1d628f6a 100644 --- a/library/std/src/io/cursor.rs +++ b/library/std/src/io/cursor.rs @@ -3,6 +3,7 @@ mod tests; use crate::io::prelude::*; +use crate::alloc::Allocator; use crate::cmp; use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, ReadBuf, SeekFrom}; @@ -398,7 +399,10 @@ fn slice_write_vectored( } // Resizing write implementation -fn vec_write(pos_mut: &mut u64, vec: &mut Vec<u8>, buf: &[u8]) -> io::Result<usize> { +fn vec_write<A>(pos_mut: &mut u64, vec: &mut Vec<u8, A>, buf: &[u8]) -> io::Result<usize> +where + A: Allocator, +{ let pos: usize = (*pos_mut).try_into().map_err(|_| { io::const_io_error!( ErrorKind::InvalidInput, @@ -426,11 +430,14 @@ fn vec_write(pos_mut: &mut u64, vec: &mut Vec<u8>, buf: &[u8]) -> io::Result<usi Ok(buf.len()) } -fn vec_write_vectored( +fn vec_write_vectored<A>( pos_mut: &mut u64, - vec: &mut Vec<u8>, + vec: &mut Vec<u8, A>, bufs: &[IoSlice<'_>], -) -> io::Result<usize> { +) -> io::Result<usize> +where + A: Allocator, +{ let mut nwritten = 0; for buf in bufs { nwritten += vec_write(pos_mut, vec, buf)?; @@ -462,7 +469,10 @@ impl Write for Cursor<&mut [u8]> { } #[stable(feature = "cursor_mut_vec", since = "1.25.0")] -impl Write for Cursor<&mut Vec<u8>> { +impl<A> Write for Cursor<&mut Vec<u8, A>> +where + A: Allocator, +{ fn write(&mut self, buf: &[u8]) -> io::Result<usize> { vec_write(&mut self.pos, self.inner, buf) } @@ -483,7 +493,10 @@ impl Write for Cursor<&mut Vec<u8>> { } #[stable(feature = "rust1", since = "1.0.0")] -impl Write for Cursor<Vec<u8>> { +impl<A> Write for Cursor<Vec<u8, A>> +where + A: Allocator, +{ fn write(&mut self, buf: &[u8]) -> io::Result<usize> { vec_write(&mut self.pos, &mut self.inner, buf) } @@ -504,7 +517,33 @@ impl Write for Cursor<Vec<u8>> { } #[stable(feature = "cursor_box_slice", since = "1.5.0")] -impl Write for Cursor<Box<[u8]>> { +impl<A> Write for Cursor<Box<[u8], A>> +where + A: Allocator, +{ + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + slice_write(&mut self.pos, &mut self.inner, buf) + } + + #[inline] + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { + slice_write_vectored(&mut self.pos, &mut self.inner, bufs) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +#[stable(feature = "cursor_array", since = "1.61.0")] +impl<const N: usize> Write for Cursor<[u8; N]> { #[inline] fn write(&mut self, buf: &[u8]) -> io::Result<usize> { slice_write(&mut self.pos, &mut self.inner, buf) diff --git a/library/std/src/io/cursor/tests.rs b/library/std/src/io/cursor/tests.rs index 5da31ce0ba7..f1ee177b7f3 100644 --- a/library/std/src/io/cursor/tests.rs +++ b/library/std/src/io/cursor/tests.rs @@ -50,9 +50,11 @@ fn test_mem_mut_writer() { assert_eq!(&writer.get_ref()[..], b); } -#[test] -fn test_box_slice_writer() { - let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice()); +fn test_slice_writer<T>(writer: &mut Cursor<T>) +where + T: AsRef<[u8]>, + Cursor<T>: Write, +{ assert_eq!(writer.position(), 0); assert_eq!(writer.write(&[0]).unwrap(), 1); assert_eq!(writer.position(), 1); @@ -65,12 +67,14 @@ fn test_box_slice_writer() { assert_eq!(writer.write(&[8, 9]).unwrap(), 1); assert_eq!(writer.write(&[10]).unwrap(), 0); let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; - assert_eq!(&**writer.get_ref(), b); + assert_eq!(writer.get_ref().as_ref(), b); } -#[test] -fn test_box_slice_writer_vectored() { - let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice()); +fn test_slice_writer_vectored<T>(writer: &mut Cursor<T>) +where + T: AsRef<[u8]>, + Cursor<T>: Write, +{ assert_eq!(writer.position(), 0); assert_eq!(writer.write_vectored(&[IoSlice::new(&[0])]).unwrap(), 1); assert_eq!(writer.position(), 1); @@ -85,53 +89,45 @@ fn test_box_slice_writer_vectored() { assert_eq!(writer.write_vectored(&[IoSlice::new(&[8, 9])]).unwrap(), 1); assert_eq!(writer.write_vectored(&[IoSlice::new(&[10])]).unwrap(), 0); let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; - assert_eq!(&**writer.get_ref(), b); + assert_eq!(writer.get_ref().as_ref(), b); +} + +#[test] +fn test_box_slice_writer() { + let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice()); + test_slice_writer(&mut writer); +} + +#[test] +fn test_box_slice_writer_vectored() { + let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice()); + test_slice_writer_vectored(&mut writer); +} + +#[test] +fn test_array_writer() { + let mut writer = Cursor::new([0u8; 9]); + test_slice_writer(&mut writer); +} + +#[test] +fn test_array_writer_vectored() { + let mut writer = Cursor::new([0u8; 9]); + test_slice_writer_vectored(&mut writer); } #[test] fn test_buf_writer() { let mut buf = [0 as u8; 9]; - { - let mut writer = Cursor::new(&mut buf[..]); - assert_eq!(writer.position(), 0); - assert_eq!(writer.write(&[0]).unwrap(), 1); - assert_eq!(writer.position(), 1); - assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); - assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); - assert_eq!(writer.position(), 8); - assert_eq!(writer.write(&[]).unwrap(), 0); - assert_eq!(writer.position(), 8); - - assert_eq!(writer.write(&[8, 9]).unwrap(), 1); - assert_eq!(writer.write(&[10]).unwrap(), 0); - } - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; - assert_eq!(buf, b); + let mut writer = Cursor::new(&mut buf[..]); + test_slice_writer(&mut writer); } #[test] fn test_buf_writer_vectored() { let mut buf = [0 as u8; 9]; - { - let mut writer = Cursor::new(&mut buf[..]); - assert_eq!(writer.position(), 0); - assert_eq!(writer.write_vectored(&[IoSlice::new(&[0])]).unwrap(), 1); - assert_eq!(writer.position(), 1); - assert_eq!( - writer - .write_vectored(&[IoSlice::new(&[1, 2, 3]), IoSlice::new(&[4, 5, 6, 7])],) - .unwrap(), - 7, - ); - assert_eq!(writer.position(), 8); - assert_eq!(writer.write_vectored(&[]).unwrap(), 0); - assert_eq!(writer.position(), 8); - - assert_eq!(writer.write_vectored(&[IoSlice::new(&[8, 9])]).unwrap(), 1); - assert_eq!(writer.write_vectored(&[IoSlice::new(&[10])]).unwrap(), 0); - } - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; - assert_eq!(buf, b); + let mut writer = Cursor::new(&mut buf[..]); + test_slice_writer_vectored(&mut writer); } #[test] diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index 17e2b97545a..4a50e647c64 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -457,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 { @@ -561,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] @@ -618,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"); /// } @@ -657,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"); /// } @@ -731,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"); /// } @@ -770,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"); /// } @@ -852,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 3fa965d08e6..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(()) //! } //! ``` @@ -1035,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(()) /// } /// ``` @@ -1761,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(); @@ -1804,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(()) /// } /// ``` @@ -1988,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(); @@ -2042,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")] @@ -2110,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 5bb70ae472b..ac6d41e13b0 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -368,10 +368,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}"), /// } /// ``` /// @@ -1014,7 +1014,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/keyword_docs.rs b/library/std/src/keyword_docs.rs index 5b76259afc1..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:#?}"); /// } /// } /// @@ -2313,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} !"), /// } /// } /// ``` @@ -2337,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 10fec8e1152..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,22 +221,18 @@ // 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_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)] @@ -248,19 +243,17 @@ #![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)] @@ -270,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)] @@ -279,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)] @@ -316,19 +303,14 @@ #![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)] @@ -338,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] @@ -384,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; @@ -516,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 { @@ -568,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/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/l4re/fs.rs b/library/std/src/os/l4re/fs.rs new file mode 100644 index 00000000000..b9b6918292f --- /dev/null +++ b/library/std/src/os/l4re/fs.rs @@ -0,0 +1,382 @@ +//! L4Re-specific extensions to primitives in the [`std::fs`] module. +//! +//! [`std::fs`]: crate::fs + +#![stable(feature = "metadata_ext", since = "1.1.0")] + +use crate::fs::Metadata; +use crate::sys_common::AsInner; + +#[allow(deprecated)] +use crate::os::l4re::raw; + +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: crate::fs::Metadata +#[stable(feature = "metadata_ext", since = "1.1.0")] +pub trait MetadataExt { + /// Gain a reference to the underlying `stat` structure which contains + /// the raw information returned by the OS. + /// + /// The contents of the returned [`stat`] are **not** consistent across + /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the + /// cross-Unix abstractions contained within the raw stat. + /// + /// [`stat`]: struct@crate::os::linux::raw::stat + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// let stat = meta.as_raw_stat(); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext", since = "1.1.0")] + #[rustc_deprecated(since = "1.8.0", reason = "other methods of this trait are now preferred")] + #[allow(deprecated)] + fn as_raw_stat(&self) -> &raw::stat; + + /// Returns the device ID on which this file resides. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_dev()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_dev(&self) -> u64; + /// Returns the inode number. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_ino()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ino(&self) -> u64; + /// Returns the file type and mode. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_mode()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mode(&self) -> u32; + /// Returns the number of hard links to file. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_nlink()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_nlink(&self) -> u64; + /// Returns the user ID of the file owner. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_uid()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_uid(&self) -> u32; + /// Returns the group ID of the file owner. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_gid()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_gid(&self) -> u32; + /// Returns the device ID that this file represents. Only relevant for special file. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_rdev()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_rdev(&self) -> u64; + /// Returns the size of the file (if it is a regular file or a symbolic link) in bytes. + /// + /// The size of a symbolic link is the length of the pathname it contains, + /// without a terminating null byte. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_size()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_size(&self) -> u64; + /// Returns the last access time of the file, in seconds since Unix Epoch. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_atime()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime(&self) -> i64; + /// Returns the last access time of the file, in nanoseconds since [`st_atime`]. + /// + /// [`st_atime`]: Self::st_atime + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_atime_nsec()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime_nsec(&self) -> i64; + /// Returns the last modification time of the file, in seconds since Unix Epoch. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_mtime()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime(&self) -> i64; + /// Returns the last modification time of the file, in nanoseconds since [`st_mtime`]. + /// + /// [`st_mtime`]: Self::st_mtime + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_mtime_nsec()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime_nsec(&self) -> i64; + /// Returns the last status change time of the file, in seconds since Unix Epoch. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_ctime()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime(&self) -> i64; + /// Returns the last status change time of the file, in nanoseconds since [`st_ctime`]. + /// + /// [`st_ctime`]: Self::st_ctime + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_ctime_nsec()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime_nsec(&self) -> i64; + /// Returns the "preferred" block size for efficient filesystem I/O. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_blksize()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blksize(&self) -> u64; + /// Returns the number of blocks allocated to the file, 512-byte units. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs; + /// use std::io; + /// use std::os::linux::fs::MetadataExt; + /// + /// fn main() -> io::Result<()> { + /// let meta = fs::metadata("some_file")?; + /// println!("{}", meta.st_blocks()); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_blocks(&self) -> u64; +} + +#[stable(feature = "metadata_ext", since = "1.1.0")] +impl MetadataExt for Metadata { + #[allow(deprecated)] + fn as_raw_stat(&self) -> &raw::stat { + unsafe { &*(self.as_inner().as_inner() as *const libc::stat64 as *const raw::stat) } + } + fn st_dev(&self) -> u64 { + self.as_inner().as_inner().st_dev as u64 + } + fn st_ino(&self) -> u64 { + self.as_inner().as_inner().st_ino as u64 + } + fn st_mode(&self) -> u32 { + self.as_inner().as_inner().st_mode as u32 + } + fn st_nlink(&self) -> u64 { + self.as_inner().as_inner().st_nlink as u64 + } + fn st_uid(&self) -> u32 { + self.as_inner().as_inner().st_uid as u32 + } + fn st_gid(&self) -> u32 { + self.as_inner().as_inner().st_gid as u32 + } + fn st_rdev(&self) -> u64 { + self.as_inner().as_inner().st_rdev as u64 + } + fn st_size(&self) -> u64 { + self.as_inner().as_inner().st_size as u64 + } + fn st_atime(&self) -> i64 { + self.as_inner().as_inner().st_atime as i64 + } + fn st_atime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_atime_nsec as i64 + } + fn st_mtime(&self) -> i64 { + self.as_inner().as_inner().st_mtime as i64 + } + fn st_mtime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_mtime_nsec as i64 + } + fn st_ctime(&self) -> i64 { + self.as_inner().as_inner().st_ctime as i64 + } + fn st_ctime_nsec(&self) -> i64 { + self.as_inner().as_inner().st_ctime_nsec as i64 + } + fn st_blksize(&self) -> u64 { + self.as_inner().as_inner().st_blksize as u64 + } + fn st_blocks(&self) -> u64 { + self.as_inner().as_inner().st_blocks as u64 + } +} diff --git a/library/std/src/os/l4re/mod.rs b/library/std/src/os/l4re/mod.rs new file mode 100644 index 00000000000..14c2425c165 --- /dev/null +++ b/library/std/src/os/l4re/mod.rs @@ -0,0 +1,7 @@ +//! L4Re-specific definitions. + +#![stable(feature = "raw_ext", since = "1.1.0")] +#![doc(cfg(target_os = "l4re"))] + +pub mod fs; +pub mod raw; diff --git a/library/std/src/os/l4re/raw.rs b/library/std/src/os/l4re/raw.rs new file mode 100644 index 00000000000..5efd6301fc9 --- /dev/null +++ b/library/std/src/os/l4re/raw.rs @@ -0,0 +1,365 @@ +//! L4Re-specific raw type definitions. + +#![stable(feature = "raw_ext", since = "1.1.0")] +#![rustc_deprecated( + since = "1.8.0", + reason = "these type aliases are no longer supported by \ + the standard library, the `libc` crate on \ + crates.io should be used instead for the correct \ + definitions" +)] +#![allow(deprecated)] + +use crate::os::raw::c_ulong; + +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type dev_t = u64; +#[stable(feature = "raw_ext", since = "1.1.0")] +pub type mode_t = u32; + +#[stable(feature = "pthread_t", since = "1.8.0")] +pub type pthread_t = c_ulong; + +#[doc(inline)] +#[stable(feature = "raw_ext", since = "1.1.0")] +pub use self::arch::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t}; + +#[cfg(any( + target_arch = "x86", + target_arch = "le32", + target_arch = "m68k", + target_arch = "powerpc", + target_arch = "sparc", + target_arch = "arm", + target_arch = "asmjs", + target_arch = "wasm32" +))] +mod arch { + use crate::os::raw::{c_long, c_short, c_uint}; + + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type blkcnt_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type blksize_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type ino_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type nlink_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type off_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type time_t = i64; + + #[repr(C)] + #[derive(Clone)] + #[stable(feature = "raw_ext", since = "1.1.0")] + pub struct stat { + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_dev: u64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub __pad1: c_short, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub __st_ino: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mode: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_nlink: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_uid: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_gid: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_rdev: u64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub __pad2: c_uint, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_size: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blksize: i32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blocks: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime: i32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime: i32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime: i32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ino: u64, + } +} + +#[cfg(target_arch = "mips")] +mod arch { + use crate::os::raw::{c_long, c_ulong}; + + #[cfg(target_env = "musl")] + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type blkcnt_t = i64; + #[cfg(not(target_env = "musl"))] + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type blkcnt_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type blksize_t = u64; + #[cfg(target_env = "musl")] + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type ino_t = u64; + #[cfg(not(target_env = "musl"))] + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type ino_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type nlink_t = u64; + #[cfg(target_env = "musl")] + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type off_t = u64; + #[cfg(not(target_env = "musl"))] + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type off_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type time_t = i64; + + #[repr(C)] + #[derive(Clone)] + #[stable(feature = "raw_ext", since = "1.1.0")] + pub struct stat { + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_dev: c_ulong, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_pad1: [c_long; 3], + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ino: u64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mode: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_nlink: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_uid: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_gid: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_rdev: c_ulong, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_pad2: [c_long; 2], + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_size: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime: i32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime: i32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime: i32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blksize: i32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blocks: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_pad5: [c_long; 14], + } +} + +#[cfg(target_arch = "hexagon")] +mod arch { + use crate::os::raw::{c_int, c_long, c_uint}; + + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type blkcnt_t = i64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type blksize_t = c_long; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type ino_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type nlink_t = c_uint; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type off_t = i64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type time_t = i64; + + #[repr(C)] + #[derive(Clone)] + #[stable(feature = "raw_ext", since = "1.1.0")] + pub struct stat { + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_dev: u64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ino: u64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mode: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_nlink: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_uid: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_gid: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_rdev: u64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub __pad1: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_size: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blksize: i32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub __pad2: i32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blocks: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub __pad3: [c_int; 2], + } +} + +#[cfg(any( + target_arch = "mips64", + target_arch = "s390x", + target_arch = "sparc64", + target_arch = "riscv64", + target_arch = "riscv32" +))] +mod arch { + pub use libc::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t}; +} + +#[cfg(target_arch = "aarch64")] +mod arch { + use crate::os::raw::{c_int, c_long}; + + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type blkcnt_t = i64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type blksize_t = i32; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type ino_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type nlink_t = u32; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type off_t = i64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type time_t = c_long; + + #[repr(C)] + #[derive(Clone)] + #[stable(feature = "raw_ext", since = "1.1.0")] + pub struct stat { + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_dev: u64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ino: u64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mode: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_nlink: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_uid: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_gid: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_rdev: u64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub __pad1: u64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_size: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blksize: i32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub __pad2: c_int, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blocks: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime: time_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime: time_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime: time_t, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub __unused: [c_int; 2], + } +} + +#[cfg(any(target_arch = "x86_64", target_arch = "powerpc64"))] +mod arch { + use crate::os::raw::{c_int, c_long}; + + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type blkcnt_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type blksize_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type ino_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type nlink_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type off_t = u64; + #[stable(feature = "raw_ext", since = "1.1.0")] + pub type time_t = i64; + + #[repr(C)] + #[derive(Clone)] + #[stable(feature = "raw_ext", since = "1.1.0")] + pub struct stat { + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_dev: u64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ino: u64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_nlink: u64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mode: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_uid: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_gid: u32, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub __pad0: c_int, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_rdev: u64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_size: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blksize: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_blocks: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_atime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_mtime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime: i64, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub st_ctime_nsec: c_long, + #[stable(feature = "raw_ext", since = "1.1.0")] + pub __unused: [c_long; 3], + } +} diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index 90c30313dbb..029f131c40b 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -81,7 +81,7 @@ pub mod unix; all(target_vendor = "fortanix", target_env = "sgx") ) )))] -#[cfg(any(target_os = "linux", target_os = "l4re", doc))] +#[cfg(any(target_os = "linux", doc))] pub mod linux; // wasi @@ -127,6 +127,8 @@ pub mod haiku; pub mod illumos; #[cfg(target_os = "ios")] pub mod ios; +#[cfg(target_os = "l4re")] +pub mod l4re; #[cfg(target_os = "macos")] pub mod macos; #[cfg(target_os = "netbsd")] 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/mod.rs b/library/std/src/os/unix/mod.rs index 62f750fa607..7b8ca79eeb8 100644 --- a/library/std/src/os/unix/mod.rs +++ b/library/std/src/os/unix/mod.rs @@ -55,7 +55,9 @@ mod platform { pub use crate::os::illumos::*; #[cfg(target_os = "ios")] pub use crate::os::ios::*; - #[cfg(any(target_os = "linux", target_os = "l4re"))] + #[cfg(target_os = "l4re")] + pub use crate::os::l4re::*; + #[cfg(target_os = "linux")] pub use crate::os::linux::*; #[cfg(target_os = "macos")] pub use crate::os::macos::*; 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/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 e544608f83c..bcf5c9328b7 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -592,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/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/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/l4re.rs b/library/std/src/sys/unix/l4re.rs index d13e1ecbbfe..f052d8f7f05 100644 --- a/library/std/src/sys/unix/l4re.rs +++ b/library/std/src/sys/unix/l4re.rs @@ -13,6 +13,7 @@ pub mod net { use crate::fmt; use crate::io::{self, IoSlice, IoSliceMut}; use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; + use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; use crate::sys::fd::FileDesc; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::time::Duration; @@ -59,7 +60,7 @@ pub mod net { } pub fn is_read_vectored(&self) -> bool { - unimpl!(); + false } pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> { @@ -83,7 +84,7 @@ pub mod net { } pub fn is_write_vectored(&self) -> bool { - unimpl!(); + false } pub fn set_timeout(&self, _: Option<Duration>, _: libc::c_int) -> io::Result<()> { @@ -121,23 +122,52 @@ pub mod net { pub fn take_error(&self) -> io::Result<Option<io::Error>> { unimpl!(); } + + // This is used by sys_common code to abstract over Windows and Unix. + pub fn as_raw(&self) -> RawFd { + self.as_raw_fd() + } + } + + impl AsInner<FileDesc> for Socket { + fn as_inner(&self) -> &FileDesc { + &self.0 + } + } + + impl FromInner<FileDesc> for Socket { + fn from_inner(file_desc: FileDesc) -> Socket { + Socket(file_desc) + } } - impl AsInner<libc::c_int> for Socket { - fn as_inner(&self) -> &libc::c_int { - self.0.as_inner() + impl IntoInner<FileDesc> for Socket { + fn into_inner(self) -> FileDesc { + self.0 } } - impl FromInner<libc::c_int> for Socket { - fn from_inner(fd: libc::c_int) -> Socket { - Socket(FileDesc::new(fd)) + impl AsFd for Socket { + fn as_fd(&self) -> BorrowedFd<'_> { + self.0.as_fd() } } - impl IntoInner<libc::c_int> for Socket { - fn into_inner(self) -> libc::c_int { - self.0.into_raw() + impl AsRawFd for Socket { + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() + } + } + + impl IntoRawFd for Socket { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw_fd() + } + } + + impl FromRawFd for Socket { + unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { + Self(FromRawFd::from_raw_fd(raw_fd)) } } @@ -191,7 +221,7 @@ pub mod net { } pub fn is_read_vectored(&self) -> bool { - unimpl!(); + false } pub fn write(&self, _: &[u8]) -> io::Result<usize> { @@ -203,7 +233,7 @@ pub mod net { } pub fn is_write_vectored(&self) -> bool { - unimpl!(); + false } pub fn peer_addr(&self) -> io::Result<SocketAddr> { @@ -497,7 +527,7 @@ pub mod net { impl LookupHost { pub fn port(&self) -> u16 { - unimpl!(); + 0 // unimplemented } } diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index 605cc499b3c..7423d90263d 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -80,6 +80,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) { target_os = "macos", target_os = "ios", target_os = "redox", + target_os = "l4re", )))] { use crate::sys::os::errno; let pfds: &mut [_] = &mut [ 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_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 07a0339c066..2a97a802a20 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -27,7 +27,10 @@ use crate::sys::weak::weak; use libc::RTP_ID as pid_t; #[cfg(not(target_os = "vxworks"))] -use libc::{c_int, gid_t, pid_t, uid_t}; +use libc::{c_int, pid_t}; + +#[cfg(not(any(target_os = "vxworks", target_os = "l4re")))] +use libc::{gid_t, uid_t}; //////////////////////////////////////////////////////////////////////////////// // Command @@ -120,7 +123,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 +651,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 +663,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 +685,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_vxworks.rs b/library/std/src/sys/unix/process/process_vxworks.rs index 56ed6cfeb6a..016bc20ec0a 100644 --- a/library/std/src/sys/unix/process/process_vxworks.rs +++ b/library/std/src/sys/unix/process/process_vxworks.rs @@ -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/thread.rs b/library/std/src/sys/unix/thread.rs index ff01ce27333..2d5d306ed62 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -384,6 +384,11 @@ fn cgroup2_quota() -> usize { 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); 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/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.rs b/library/std/src/sys/windows/process.rs index fafd1412d4c..a13585a0222 100644 --- a/library/std/src/sys/windows/process.rs +++ b/library/std/src/sys/windows/process.rs @@ -19,12 +19,12 @@ use crate::path::{Path, PathBuf}; use crate::ptr; use crate::sys::c; use crate::sys::c::NonZeroDWORD; +use crate::sys::cvt; use crate::sys::fs::{File, OpenOptions}; use crate::sys::handle::Handle; use crate::sys::path; use crate::sys::pipe::{self, AnonPipe}; use crate::sys::stdio; -use crate::sys::{cvt, to_u16s}; use crate::sys_common::mutex::StaticMutex; use crate::sys_common::process::{CommandEnv, CommandEnvs}; use crate::sys_common::{AsInner, IntoInner}; @@ -269,8 +269,13 @@ impl Command { None }; let program = resolve_exe(&self.program, || env::var_os("PATH"), child_paths)?; + // Case insensitive "ends_with" of UTF-16 encoded ".bat" or ".cmd" + let is_batch_file = matches!( + program.len().checked_sub(5).and_then(|i| program.get(i..)), + Some([46, 98 | 66, 97 | 65, 116 | 84, 0] | [46, 99 | 67, 109 | 77, 100 | 68, 0]) + ); let mut cmd_str = - make_command_line(program.as_os_str(), &self.args, self.force_quotes_enabled)?; + make_command_line(&program, &self.args, self.force_quotes_enabled, is_batch_file)?; cmd_str.push(0); // add null terminator // stolen from the libuv code. @@ -309,7 +314,6 @@ impl Command { si.hStdOutput = stdout.as_raw_handle(); si.hStdError = stderr.as_raw_handle(); - let program = to_u16s(&program)?; unsafe { cvt(c::CreateProcessW( program.as_ptr(), @@ -366,7 +370,7 @@ fn resolve_exe<'a>( exe_path: &'a OsStr, parent_paths: impl FnOnce() -> Option<OsString>, child_paths: Option<&OsStr>, -) -> io::Result<PathBuf> { +) -> io::Result<Vec<u16>> { // Early return if there is no filename. if exe_path.is_empty() || path::has_trailing_slash(exe_path) { return Err(io::const_io_error!( @@ -388,19 +392,19 @@ fn resolve_exe<'a>( if has_exe_suffix { // The application name is a path to a `.exe` file. // Let `CreateProcessW` figure out if it exists or not. - return Ok(exe_path.into()); + return path::maybe_verbatim(Path::new(exe_path)); } let mut path = PathBuf::from(exe_path); // Append `.exe` if not already there. path = path::append_suffix(path, EXE_SUFFIX.as_ref()); - if program_exists(&path) { + if let Some(path) = program_exists(&path) { return Ok(path); } else { // It's ok to use `set_extension` here because the intent is to // remove the extension that was just added. path.set_extension(""); - return Ok(path); + return path::maybe_verbatim(&path); } } else { ensure_no_nuls(exe_path)?; @@ -415,7 +419,7 @@ fn resolve_exe<'a>( if !has_extension { path.set_extension(EXE_EXTENSION); } - if program_exists(&path) { Some(path) } else { None } + program_exists(&path) }); if let Some(path) = result { return Ok(path); @@ -431,10 +435,10 @@ fn search_paths<Paths, Exists>( parent_paths: Paths, child_paths: Option<&OsStr>, mut exists: Exists, -) -> Option<PathBuf> +) -> Option<Vec<u16>> where Paths: FnOnce() -> Option<OsString>, - Exists: FnMut(PathBuf) -> Option<PathBuf>, + Exists: FnMut(PathBuf) -> Option<Vec<u16>>, { // 1. Child paths // This is for consistency with Rust's historic behaviour. @@ -486,17 +490,18 @@ where } /// Check if a file exists without following symlinks. -fn program_exists(path: &Path) -> bool { +fn program_exists(path: &Path) -> Option<Vec<u16>> { unsafe { - to_u16s(path) - .map(|path| { - // Getting attributes using `GetFileAttributesW` does not follow symlinks - // and it will almost always be successful if the link exists. - // There are some exceptions for special system files (e.g. the pagefile) - // but these are not executable. - c::GetFileAttributesW(path.as_ptr()) != c::INVALID_FILE_ATTRIBUTES - }) - .unwrap_or(false) + let path = path::maybe_verbatim(path).ok()?; + // Getting attributes using `GetFileAttributesW` does not follow symlinks + // and it will almost always be successful if the link exists. + // There are some exceptions for special system files (e.g. the pagefile) + // but these are not executable. + if c::GetFileAttributesW(path.as_ptr()) == c::INVALID_FILE_ATTRIBUTES { + None + } else { + Some(path) + } } } @@ -730,7 +735,12 @@ enum Quote { // Produces a wide string *without terminating null*; returns an error if // `prog` or any of the `args` contain a nul. -fn make_command_line(prog: &OsStr, args: &[Arg], force_quotes: bool) -> io::Result<Vec<u16>> { +fn make_command_line( + prog: &[u16], + args: &[Arg], + force_quotes: bool, + is_batch_file: bool, +) -> io::Result<Vec<u16>> { // Encode the command and arguments in a command line string such // that the spawned process may recover them using CommandLineToArgvW. let mut cmd: Vec<u16> = Vec::new(); @@ -739,17 +749,18 @@ fn make_command_line(prog: &OsStr, args: &[Arg], force_quotes: bool) -> io::Resu // need to add an extra pair of quotes surrounding the whole command line // so they are properly passed on to the script. // See issue #91991. - let is_batch_file = Path::new(prog) - .extension() - .map(|ext| ext.eq_ignore_ascii_case("cmd") || ext.eq_ignore_ascii_case("bat")) - .unwrap_or(false); if is_batch_file { cmd.push(b'"' as u16); } - // Always quote the program name so CreateProcess doesn't interpret args as - // part of the name if the binary wasn't found first time. - append_arg(&mut cmd, prog, Quote::Always)?; + // Always quote the program name so CreateProcess to avoid ambiguity when + // the child process parses its arguments. + // Note that quotes aren't escaped here because they can't be used in arg0. + // But that's ok because file paths can't contain quotes. + cmd.push(b'"' as u16); + cmd.extend_from_slice(prog.strip_suffix(&[0]).unwrap_or(prog)); + cmd.push(b'"' as u16); + for arg in args { cmd.push(' ' as u16); let (arg, quote) = match arg { diff --git a/library/std/src/sys/windows/process/tests.rs b/library/std/src/sys/windows/process/tests.rs index d18c3d855bc..96477fb19da 100644 --- a/library/std/src/sys/windows/process/tests.rs +++ b/library/std/src/sys/windows/process/tests.rs @@ -3,11 +3,12 @@ use super::Arg; use crate::env; use crate::ffi::{OsStr, OsString}; use crate::process::Command; +use crate::sys::to_u16s; #[test] fn test_raw_args() { let command_line = &make_command_line( - OsStr::new("quoted exe"), + &to_u16s("quoted exe").unwrap(), &[ Arg::Regular(OsString::from("quote me")), Arg::Raw(OsString::from("quote me *not*")), @@ -16,6 +17,7 @@ fn test_raw_args() { Arg::Regular(OsString::from("optional-quotes")), ], false, + false, ) .unwrap(); assert_eq!( @@ -28,9 +30,10 @@ fn test_raw_args() { fn test_make_command_line() { fn test_wrapper(prog: &str, args: &[&str], force_quotes: bool) -> String { let command_line = &make_command_line( - OsStr::new(prog), + &to_u16s(prog).unwrap(), &args.iter().map(|a| Arg::Regular(OsString::from(a))).collect::<Vec<_>>(), force_quotes, + false, ) .unwrap(); String::from_utf16(command_line).unwrap() @@ -121,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 bd304dc5737..2f469513eb4 100644 --- a/library/std/src/sys/windows/thread.rs +++ b/library/std/src/sys/windows/thread.rs @@ -30,12 +30,9 @@ 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, 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/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 2464a0e2e47..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")] @@ -178,7 +179,9 @@ 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(always))] // see comments below - unsafe fn __getit() -> $crate::option::Option<&'static $t> { + 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() + }) + } } } @@ -298,7 +312,9 @@ macro_rules! __thread_local_inner { // // The issue of "should enable on Windows sometimes" is #84933 #[cfg_attr(not(windows), inline(always))] - unsafe fn __getit() -> $crate::option::Option<&'static $t> { + 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 09d1e714ab6..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 } } 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); |
