From fc126df5a7bf6cf74a8fcf16d2f8c2902c7d9e73 Mon Sep 17 00:00:00 2001 From: Hegui Dai Date: Wed, 26 Mar 2025 08:23:43 +0800 Subject: [PATCH 01/17] Update the index.html of Option to make the summary more comprehensive --- library/core/src/option.rs | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 7ec0ac712714..ee755f6629e5 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -159,11 +159,17 @@ //! //! ## Querying the variant //! -//! The [`is_some`] and [`is_none`] methods return [`true`] if the [`Option`] -//! is [`Some`] or [`None`], respectively. +//! The [`is_some`] and [`is_none`] methods take a borrow of the [`Option`] +//! and return [`true`] if the [`Option`] is [`Some`] or [`None`], respectively. +//! +//! The [`is_some_and`] and [`is_none_or`] methods take ownership of the [`Option`] +//! and apply the provided function to make a decision. +//! The methods return the same boolean value as the function returns. //! //! [`is_none`]: Option::is_none //! [`is_some`]: Option::is_some +//! [`is_some_and`]: Option::is_some_and +//! [`is_none_or`]: Option::is_none_or //! //! ## Adapters for working with references //! @@ -177,6 +183,10 @@ //! [Option]<[Pin]<[&]T>> //! * [`as_pin_mut`] converts from [Pin]<[&mut] [Option]\> to //! [Option]<[Pin]<[&mut] T>> +//! * [`as_slice`] returns a slice of the contained value, if any. +//! If this is [`None`], an empty slice is returned. +//! * [`as_mut_slice`] returns a mutable slice of the contained value, if any. +//! If this is [`None`], an empty slice is returned. //! //! [&]: reference "shared reference" //! [&mut]: reference "mutable reference" @@ -187,6 +197,8 @@ //! [`as_pin_mut`]: Option::as_pin_mut //! [`as_pin_ref`]: Option::as_pin_ref //! [`as_ref`]: Option::as_ref +//! [`as_slice`]: Option::as_slice +//! [`as_mut_slice`]: Option::as_mut_slice //! //! ## Extracting the contained value //! @@ -200,12 +212,16 @@ //! (which must implement the [`Default`] trait) //! * [`unwrap_or_else`] returns the result of evaluating the provided //! function +//! * [`unwrap_unchecked`] returns the contained value, without checking +//! calling this method on None is *[undefined behavior]* //! //! [`expect`]: Option::expect //! [`unwrap`]: Option::unwrap //! [`unwrap_or`]: Option::unwrap_or //! [`unwrap_or_default`]: Option::unwrap_or_default //! [`unwrap_or_else`]: Option::unwrap_or_else +//! [`unwrap_unchecked`]: Option::unwrap_unchecked +//! [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html //! //! ## Transforming contained values //! @@ -232,6 +248,8 @@ //! if the function returns `true`; otherwise, returns [`None`] //! * [`flatten`] removes one level of nesting from an //! [`Option>`] +//! * [`insert`] calls the provided function with a reference to +//! the contained value if [`Some`] //! * [`map`] transforms [`Option`] to [`Option`] by applying the //! provided function to the contained value of [`Some`] and leaving //! [`None`] values unchanged @@ -239,6 +257,7 @@ //! [`Some(t)`]: Some //! [`filter`]: Option::filter //! [`flatten`]: Option::flatten +//! [`insert`]: Option::insert //! [`map`]: Option::map //! //! These methods transform [`Option`] to a value of a possibly From 159ae8fcee04302d24c9d1afc077697b8f266e11 Mon Sep 17 00:00:00 2001 From: Hegui Dai Date: Wed, 26 Mar 2025 14:50:03 +0800 Subject: [PATCH 02/17] Keeps the inspect() classification the same as in Result --- library/core/src/option.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index ee755f6629e5..a1f0224c7791 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -171,6 +171,13 @@ //! [`is_some_and`]: Option::is_some_and //! [`is_none_or`]: Option::is_none_or //! +//! ## Inspecting the variant +//! +//! The [`inspect`] method takes ownership of the [`Option`] +//! and applies the provided function to the contained value by reference if [`Some`] +//! +//! [`inspect`]: Option::inspect +//! //! ## Adapters for working with references //! //! * [`as_ref`] converts from [&][][Option]\ to [Option]<[&]T> @@ -248,8 +255,6 @@ //! if the function returns `true`; otherwise, returns [`None`] //! * [`flatten`] removes one level of nesting from an //! [`Option>`] -//! * [`insert`] calls the provided function with a reference to -//! the contained value if [`Some`] //! * [`map`] transforms [`Option`] to [`Option`] by applying the //! provided function to the contained value of [`Some`] and leaving //! [`None`] values unchanged @@ -257,7 +262,6 @@ //! [`Some(t)`]: Some //! [`filter`]: Option::filter //! [`flatten`]: Option::flatten -//! [`insert`]: Option::insert //! [`map`]: Option::map //! //! These methods transform [`Option`] to a value of a possibly From edfef428f7f80d17f7e2f1bf0620a01b9ac6621e Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Fri, 18 Apr 2025 09:40:54 +0300 Subject: [PATCH 03/17] ensure compiler existance of tools on the dist step Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/dist.rs | 23 +++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 83f71aeed720..97afcb6867cf 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -421,13 +421,13 @@ impl Step for Rustc { builder.install(&rustdoc, &image.join("bin"), FileType::Executable); } + let ra_proc_macro_srv_compiler = + builder.compiler_for(compiler.stage, builder.config.build, compiler.host); + builder.ensure(compile::Rustc::new(ra_proc_macro_srv_compiler, compiler.host)); + if let Some(ra_proc_macro_srv) = builder.ensure_if_default( tool::RustAnalyzerProcMacroSrv { - compiler: builder.compiler_for( - compiler.stage, - builder.config.build, - compiler.host, - ), + compiler: ra_proc_macro_srv_compiler, target: compiler.host, }, builder.kind, @@ -1177,6 +1177,8 @@ impl Step for Cargo { let compiler = self.compiler; let target = self.target; + builder.ensure(compile::Rustc::new(compiler, target)); + let cargo = builder.ensure(tool::Cargo { compiler, target }); let src = builder.src.join("src/tools/cargo"); let etc = src.join("src/etc"); @@ -1231,6 +1233,8 @@ impl Step for RustAnalyzer { let compiler = self.compiler; let target = self.target; + builder.ensure(compile::Rustc::new(compiler, target)); + let rust_analyzer = builder.ensure(tool::RustAnalyzer { compiler, target }); let mut tarball = Tarball::new(builder, "rust-analyzer", &target.triple); @@ -1273,6 +1277,8 @@ impl Step for Clippy { let compiler = self.compiler; let target = self.target; + builder.ensure(compile::Rustc::new(compiler, target)); + // Prepare the image directory // We expect clippy to build, because we've exited this step above if tool // state for clippy isn't testing. @@ -1323,9 +1329,12 @@ impl Step for Miri { if !builder.build.unstable_features() { return None; } + let compiler = self.compiler; let target = self.target; + builder.ensure(compile::Rustc::new(compiler, target)); + let miri = builder.ensure(tool::Miri { compiler, target }); let cargomiri = builder.ensure(tool::CargoMiri { compiler, target }); @@ -1462,6 +1471,8 @@ impl Step for Rustfmt { let compiler = self.compiler; let target = self.target; + builder.ensure(compile::Rustc::new(compiler, target)); + let rustfmt = builder.ensure(tool::Rustfmt { compiler, target }); let cargofmt = builder.ensure(tool::Cargofmt { compiler, target }); let mut tarball = Tarball::new(builder, "rustfmt", &target.triple); @@ -2327,6 +2338,8 @@ impl Step for LlvmBitcodeLinker { let compiler = self.compiler; let target = self.target; + builder.ensure(compile::Rustc::new(compiler, target)); + let llbc_linker = builder.ensure(tool::LlvmBitcodeLinker { compiler, target, extra_features: vec![] }); From 4ba9fffba53d8e9b38d37af64b4d965bf388cee4 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Fri, 18 Apr 2025 09:03:17 +0000 Subject: [PATCH 04/17] add regression test for dist compilation Signed-off-by: onur-ozkan --- src/bootstrap/src/core/builder/tests.rs | 32 +++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index fd3b28e4e6ab..9a724ec34899 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -408,6 +408,7 @@ mod dist { use pretty_assertions::assert_eq; use super::{Config, TEST_TRIPLE_1, TEST_TRIPLE_2, TEST_TRIPLE_3, first, run_build}; + use crate::Flags; use crate::core::builder::*; fn configure(host: &[&str], target: &[&str]) -> Config { @@ -646,6 +647,37 @@ mod dist { ); } + /// This also serves as an important regression test for + /// and . + #[test] + fn dist_all_cross() { + let cmd_args = + &["dist", "--stage", "2", "--dry-run", "--config=/does/not/exist"].map(str::to_owned); + let config_str = r#" + [rust] + channel = "nightly" + + [build] + extended = true + + build = "i686-unknown-haiku" + host = ["i686-unknown-netbsd"] + target = ["i686-unknown-netbsd"] + "#; + let config = Config::parse_inner(Flags::parse(cmd_args), |&_| toml::from_str(config_str)); + let mut cache = run_build(&[], config); + + // Stage 2 `compile::Rustc` should **NEVER** be cached here. + assert_eq!( + first(cache.all::()), + &[ + rustc!(TEST_TRIPLE_1 => TEST_TRIPLE_1, stage = 0), + rustc!(TEST_TRIPLE_1 => TEST_TRIPLE_1, stage = 1), + rustc!(TEST_TRIPLE_1 => TEST_TRIPLE_3, stage = 1), + ] + ); + } + #[test] fn build_all() { let build = Build::new(configure( From ea0b6cba06b01428ada0fddff5adb922fa28370f Mon Sep 17 00:00:00 2001 From: Hegui Dai Date: Mon, 21 Apr 2025 09:54:11 +0800 Subject: [PATCH 05/17] Solved suggestions --- library/core/src/option.rs | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index a1f0224c7791..9789912719b1 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -159,25 +159,18 @@ //! //! ## Querying the variant //! -//! The [`is_some`] and [`is_none`] methods take a borrow of the [`Option`] +//! The [`is_some`] and [`is_none`] methods borrow of the [`Option`] //! and return [`true`] if the [`Option`] is [`Some`] or [`None`], respectively. //! -//! The [`is_some_and`] and [`is_none_or`] methods take ownership of the [`Option`] -//! and apply the provided function to make a decision. -//! The methods return the same boolean value as the function returns. +//! The [`is_some_and`] and [`is_none_or`] methods apply the provided function +//! to the contents of the [`Option`] to produce a boolean value. +//! If this is [`None`] then a default result is returned instead without executing the function. //! //! [`is_none`]: Option::is_none //! [`is_some`]: Option::is_some //! [`is_some_and`]: Option::is_some_and //! [`is_none_or`]: Option::is_none_or //! -//! ## Inspecting the variant -//! -//! The [`inspect`] method takes ownership of the [`Option`] -//! and applies the provided function to the contained value by reference if [`Some`] -//! -//! [`inspect`]: Option::inspect -//! //! ## Adapters for working with references //! //! * [`as_ref`] converts from [&][][Option]\ to [Option]<[&]T> @@ -190,9 +183,9 @@ //! [Option]<[Pin]<[&]T>> //! * [`as_pin_mut`] converts from [Pin]<[&mut] [Option]\> to //! [Option]<[Pin]<[&mut] T>> -//! * [`as_slice`] returns a slice of the contained value, if any. +//! * [`as_slice`] returns a one-element slice of the contained value, if any. //! If this is [`None`], an empty slice is returned. -//! * [`as_mut_slice`] returns a mutable slice of the contained value, if any. +//! * [`as_mut_slice`] returns a mutable one-element slice of the contained value, if any. //! If this is [`None`], an empty slice is returned. //! //! [&]: reference "shared reference" @@ -219,8 +212,7 @@ //! (which must implement the [`Default`] trait) //! * [`unwrap_or_else`] returns the result of evaluating the provided //! function -//! * [`unwrap_unchecked`] returns the contained value, without checking -//! calling this method on None is *[undefined behavior]* +//! * [`unwrap_unchecked`] produces *[undefined behavior]* //! //! [`expect`]: Option::expect //! [`unwrap`]: Option::unwrap @@ -253,8 +245,9 @@ //! * [`filter`] calls the provided predicate function on the contained //! value `t` if the [`Option`] is [`Some(t)`], and returns [`Some(t)`] //! if the function returns `true`; otherwise, returns [`None`] -//! * [`flatten`] removes one level of nesting from an -//! [`Option>`] +//! * [`flatten`] removes one level of nesting from an [`Option>`] +//! * [`inspect`] method takes ownership of the [`Option`] and applies +//! the provided function to the contained value by reference if [`Some`] //! * [`map`] transforms [`Option`] to [`Option`] by applying the //! provided function to the contained value of [`Some`] and leaving //! [`None`] values unchanged @@ -262,6 +255,7 @@ //! [`Some(t)`]: Some //! [`filter`]: Option::filter //! [`flatten`]: Option::flatten +//! [`inspect`]: Option::inspect //! [`map`]: Option::map //! //! These methods transform [`Option`] to a value of a possibly From 90fe2805df75b9d46b985346f0dff2690c285330 Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Mon, 21 Apr 2025 20:56:43 -0700 Subject: [PATCH 06/17] Move `sys::pal::os::Env` into `sys::env` Although `Env` (as `Vars`), `Args`, path functions, and OS constants are publicly exposed via `std::env`, their implementations are each self-contained. Keep them separate in `std::sys` and make a new module, `sys::env`, for `Env`. --- library/std/src/env.rs | 12 +- library/std/src/sys/env/hermit.rs | 116 +++++++++++++ library/std/src/sys/env/mod.rs | 37 +++++ library/std/src/sys/env/sgx.rs | 102 ++++++++++++ library/std/src/sys/env/solid.rs | 140 ++++++++++++++++ library/std/src/sys/env/uefi.rs | 138 ++++++++++++++++ library/std/src/sys/env/unix.rs | 172 +++++++++++++++++++ library/std/src/sys/env/unsupported.rs | 43 +++++ library/std/src/sys/env/wasi.rs | 146 +++++++++++++++++ library/std/src/sys/env/windows.rs | 133 +++++++++++++++ library/std/src/sys/env/xous.rs | 99 +++++++++++ library/std/src/sys/env/zkvm.rs | 63 +++++++ library/std/src/sys/mod.rs | 1 + library/std/src/sys/pal/hermit/mod.rs | 8 +- library/std/src/sys/pal/hermit/os.rs | 118 +------------ library/std/src/sys/pal/sgx/os.rs | 100 +---------- library/std/src/sys/pal/solid/os.rs | 142 +--------------- library/std/src/sys/pal/teeos/os.rs | 41 ----- library/std/src/sys/pal/uefi/os.rs | 136 --------------- library/std/src/sys/pal/unix/os.rs | 173 +------------------- library/std/src/sys/pal/unsupported/os.rs | 41 ----- library/std/src/sys/pal/wasi/os.rs | 150 +---------------- library/std/src/sys/pal/windows/os.rs | 135 +-------------- library/std/src/sys/pal/xous/os.rs | 100 +---------- library/std/src/sys/pal/zkvm/os.rs | 62 +------ library/std/src/sys/process/unix/unix.rs | 14 +- library/std/src/sys/process/unix/vxworks.rs | 4 +- 27 files changed, 1228 insertions(+), 1198 deletions(-) create mode 100644 library/std/src/sys/env/hermit.rs create mode 100644 library/std/src/sys/env/mod.rs create mode 100644 library/std/src/sys/env/sgx.rs create mode 100644 library/std/src/sys/env/solid.rs create mode 100644 library/std/src/sys/env/uefi.rs create mode 100644 library/std/src/sys/env/unix.rs create mode 100644 library/std/src/sys/env/unsupported.rs create mode 100644 library/std/src/sys/env/wasi.rs create mode 100644 library/std/src/sys/env/windows.rs create mode 100644 library/std/src/sys/env/xous.rs create mode 100644 library/std/src/sys/env/zkvm.rs diff --git a/library/std/src/env.rs b/library/std/src/env.rs index c84a72c4fad0..1593969e114a 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -13,7 +13,7 @@ use crate::error::Error; use crate::ffi::{OsStr, OsString}; use crate::path::{Path, PathBuf}; -use crate::sys::os as os_imp; +use crate::sys::{env as env_imp, os as os_imp}; use crate::{fmt, io, sys}; /// Returns the current working directory as a [`PathBuf`]. @@ -96,7 +96,7 @@ pub struct Vars { /// [`env::vars_os()`]: vars_os #[stable(feature = "env", since = "1.0.0")] pub struct VarsOs { - inner: os_imp::Env, + inner: env_imp::Env, } /// Returns an iterator of (variable, value) pairs of strings, for all the @@ -150,7 +150,7 @@ pub fn vars() -> Vars { #[must_use] #[stable(feature = "env", since = "1.0.0")] pub fn vars_os() -> VarsOs { - VarsOs { inner: os_imp::env() } + VarsOs { inner: env_imp::env() } } #[stable(feature = "env", since = "1.0.0")] @@ -259,7 +259,7 @@ pub fn var_os>(key: K) -> Option { } fn _var_os(key: &OsStr) -> Option { - os_imp::getenv(key) + env_imp::getenv(key) } /// The error type for operations interacting with environment variables. @@ -363,7 +363,7 @@ impl Error for VarError { #[stable(feature = "env", since = "1.0.0")] pub unsafe fn set_var, V: AsRef>(key: K, value: V) { let (key, value) = (key.as_ref(), value.as_ref()); - unsafe { os_imp::setenv(key, value) }.unwrap_or_else(|e| { + unsafe { env_imp::setenv(key, value) }.unwrap_or_else(|e| { panic!("failed to set environment variable `{key:?}` to `{value:?}`: {e}") }) } @@ -434,7 +434,7 @@ pub unsafe fn set_var, V: AsRef>(key: K, value: V) { #[stable(feature = "env", since = "1.0.0")] pub unsafe fn remove_var>(key: K) { let key = key.as_ref(); - unsafe { os_imp::unsetenv(key) } + unsafe { env_imp::unsetenv(key) } .unwrap_or_else(|e| panic!("failed to remove environment variable `{key:?}`: {e}")) } diff --git a/library/std/src/sys/env/hermit.rs b/library/std/src/sys/env/hermit.rs new file mode 100644 index 000000000000..4c7d7e80a350 --- /dev/null +++ b/library/std/src/sys/env/hermit.rs @@ -0,0 +1,116 @@ +use core::slice::memchr; + +use crate::collections::HashMap; +use crate::ffi::{CStr, OsStr, OsString, c_char}; +use crate::os::hermit::ffi::OsStringExt; +use crate::sync::Mutex; +use crate::{fmt, io, vec}; + +static ENV: Mutex>> = Mutex::new(None); + +pub fn init(env: *const *const c_char) { + let mut guard = ENV.lock().unwrap(); + let map = guard.insert(HashMap::new()); + + if env.is_null() { + return; + } + + unsafe { + let mut environ = env; + while !(*environ).is_null() { + if let Some((key, value)) = parse(CStr::from_ptr(*environ).to_bytes()) { + map.insert(key, value); + } + environ = environ.add(1); + } + } + + fn parse(input: &[u8]) -> Option<(OsString, OsString)> { + // Strategy (copied from glibc): Variable name and value are separated + // by an ASCII equals sign '='. Since a variable name must not be + // empty, allow variable names starting with an equals sign. Skip all + // malformed lines. + if input.is_empty() { + return None; + } + let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1); + pos.map(|p| { + ( + OsStringExt::from_vec(input[..p].to_vec()), + OsStringExt::from_vec(input[p + 1..].to_vec()), + ) + }) + } +} + +pub struct Env { + iter: vec::IntoIter<(OsString, OsString)>, +} + +// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. +pub struct EnvStrDebug<'a> { + slice: &'a [(OsString, OsString)], +} + +impl fmt::Debug for EnvStrDebug<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { slice } = self; + f.debug_list() + .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap()))) + .finish() + } +} + +impl Env { + pub fn str_debug(&self) -> impl fmt::Debug + '_ { + let Self { iter } = self; + EnvStrDebug { slice: iter.as_slice() } + } +} + +impl fmt::Debug for Env { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { iter } = self; + f.debug_list().entries(iter.as_slice()).finish() + } +} + +impl !Send for Env {} +impl !Sync for Env {} + +impl Iterator for Env { + type Item = (OsString, OsString); + fn next(&mut self) -> Option<(OsString, OsString)> { + self.iter.next() + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +/// Returns a vector of (variable, value) byte-vector pairs for all the +/// environment variables of the current process. +pub fn env() -> Env { + let guard = ENV.lock().unwrap(); + let env = guard.as_ref().unwrap(); + + let result = env.iter().map(|(key, value)| (key.clone(), value.clone())).collect::>(); + + Env { iter: result.into_iter() } +} + +pub fn getenv(k: &OsStr) -> Option { + ENV.lock().unwrap().as_ref().unwrap().get(k).cloned() +} + +pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { + let (k, v) = (k.to_owned(), v.to_owned()); + ENV.lock().unwrap().as_mut().unwrap().insert(k, v); + Ok(()) +} + +pub unsafe fn unsetenv(k: &OsStr) -> io::Result<()> { + ENV.lock().unwrap().as_mut().unwrap().remove(k); + Ok(()) +} diff --git a/library/std/src/sys/env/mod.rs b/library/std/src/sys/env/mod.rs new file mode 100644 index 000000000000..bfd3e7fe8bed --- /dev/null +++ b/library/std/src/sys/env/mod.rs @@ -0,0 +1,37 @@ +//! Platform-dependent environment variables abstraction. + +#![deny(unsafe_op_in_unsafe_fn)] + +cfg_if::cfg_if! { + if #[cfg(target_family = "unix")] { + mod unix; + pub use unix::*; + } else if #[cfg(target_family = "windows")] { + mod windows; + pub use windows::*; + } else if #[cfg(target_os = "hermit")] { + mod hermit; + pub use hermit::*; + } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] { + mod sgx; + pub use sgx::*; + } else if #[cfg(target_os = "solid_asp3")] { + mod solid; + pub use solid::*; + } else if #[cfg(target_os = "uefi")] { + mod uefi; + pub use uefi::*; + } else if #[cfg(target_os = "wasi")] { + mod wasi; + pub use wasi::*; + } else if #[cfg(target_os = "xous")] { + mod xous; + pub use xous::*; + } else if #[cfg(target_os = "zkvm")] { + mod zkvm; + pub use zkvm::*; + } else { + mod unsupported; + pub use unsupported::*; + } +} diff --git a/library/std/src/sys/env/sgx.rs b/library/std/src/sys/env/sgx.rs new file mode 100644 index 000000000000..7a48fb1872ba --- /dev/null +++ b/library/std/src/sys/env/sgx.rs @@ -0,0 +1,102 @@ +#![allow(fuzzy_provenance_casts)] // FIXME: this module systematically confuses pointers and integers + +use crate::collections::HashMap; +use crate::ffi::{OsStr, OsString}; +use crate::sync::atomic::{AtomicUsize, Ordering}; +use crate::sync::{Mutex, Once}; +use crate::{fmt, io, vec}; + +// Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests +#[cfg_attr(test, linkage = "available_externally")] +#[unsafe(export_name = "_ZN16__rust_internals3std3sys3pal3sgx2os3ENVE")] +static ENV: AtomicUsize = AtomicUsize::new(0); +// Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests +#[cfg_attr(test, linkage = "available_externally")] +#[unsafe(export_name = "_ZN16__rust_internals3std3sys3pal3sgx2os8ENV_INITE")] +static ENV_INIT: Once = Once::new(); +type EnvStore = Mutex>; + +fn get_env_store() -> Option<&'static EnvStore> { + unsafe { (ENV.load(Ordering::Relaxed) as *const EnvStore).as_ref() } +} + +fn create_env_store() -> &'static EnvStore { + ENV_INIT.call_once(|| { + ENV.store(Box::into_raw(Box::new(EnvStore::default())) as _, Ordering::Relaxed) + }); + unsafe { &*(ENV.load(Ordering::Relaxed) as *const EnvStore) } +} + +pub struct Env { + iter: vec::IntoIter<(OsString, OsString)>, +} + +// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. +pub struct EnvStrDebug<'a> { + slice: &'a [(OsString, OsString)], +} + +impl fmt::Debug for EnvStrDebug<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { slice } = self; + f.debug_list() + .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap()))) + .finish() + } +} + +impl Env { + pub fn str_debug(&self) -> impl fmt::Debug + '_ { + let Self { iter } = self; + EnvStrDebug { slice: iter.as_slice() } + } +} + +impl fmt::Debug for Env { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { iter } = self; + f.debug_list().entries(iter.as_slice()).finish() + } +} + +impl !Send for Env {} +impl !Sync for Env {} + +impl Iterator for Env { + type Item = (OsString, OsString); + fn next(&mut self) -> Option<(OsString, OsString)> { + self.iter.next() + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +pub fn env() -> Env { + let clone_to_vec = |map: &HashMap| -> Vec<_> { + map.iter().map(|(k, v)| (k.clone(), v.clone())).collect() + }; + + let iter = get_env_store() + .map(|env| clone_to_vec(&env.lock().unwrap())) + .unwrap_or_default() + .into_iter(); + Env { iter } +} + +pub fn getenv(k: &OsStr) -> Option { + get_env_store().and_then(|s| s.lock().unwrap().get(k).cloned()) +} + +pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { + let (k, v) = (k.to_owned(), v.to_owned()); + create_env_store().lock().unwrap().insert(k, v); + Ok(()) +} + +pub unsafe fn unsetenv(k: &OsStr) -> io::Result<()> { + if let Some(env) = get_env_store() { + env.lock().unwrap().remove(k); + } + Ok(()) +} diff --git a/library/std/src/sys/env/solid.rs b/library/std/src/sys/env/solid.rs new file mode 100644 index 000000000000..0eb801c996ad --- /dev/null +++ b/library/std/src/sys/env/solid.rs @@ -0,0 +1,140 @@ +use core::slice::memchr; + +use crate::ffi::{CStr, OsStr, OsString}; +use crate::os::raw::{c_char, c_int}; +use crate::os::solid::ffi::{OsStrExt, OsStringExt}; +use crate::sync::{PoisonError, RwLock}; +use crate::sys::common::small_c_string::run_with_cstr; +use crate::{fmt, io, vec}; + +static ENV_LOCK: RwLock<()> = RwLock::new(()); + +pub fn env_read_lock() -> impl Drop { + ENV_LOCK.read().unwrap_or_else(PoisonError::into_inner) +} + +pub struct Env { + iter: vec::IntoIter<(OsString, OsString)>, +} + +// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. +pub struct EnvStrDebug<'a> { + slice: &'a [(OsString, OsString)], +} + +impl fmt::Debug for EnvStrDebug<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { slice } = self; + f.debug_list() + .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap()))) + .finish() + } +} + +impl Env { + pub fn str_debug(&self) -> impl fmt::Debug + '_ { + let Self { iter } = self; + EnvStrDebug { slice: iter.as_slice() } + } +} + +impl fmt::Debug for Env { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { iter } = self; + f.debug_list().entries(iter.as_slice()).finish() + } +} + +impl !Send for Env {} +impl !Sync for Env {} + +impl Iterator for Env { + type Item = (OsString, OsString); + fn next(&mut self) -> Option<(OsString, OsString)> { + self.iter.next() + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +/// Returns a vector of (variable, value) byte-vector pairs for all the +/// environment variables of the current process. +pub fn env() -> Env { + unsafe extern "C" { + static mut environ: *const *const c_char; + } + + unsafe { + let _guard = env_read_lock(); + let mut result = Vec::new(); + if !environ.is_null() { + while !(*environ).is_null() { + if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) { + result.push(key_value); + } + environ = environ.add(1); + } + } + return Env { iter: result.into_iter() }; + } + + fn parse(input: &[u8]) -> Option<(OsString, OsString)> { + // Strategy (copied from glibc): Variable name and value are separated + // by an ASCII equals sign '='. Since a variable name must not be + // empty, allow variable names starting with an equals sign. Skip all + // malformed lines. + if input.is_empty() { + return None; + } + let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1); + pos.map(|p| { + ( + OsStringExt::from_vec(input[..p].to_vec()), + OsStringExt::from_vec(input[p + 1..].to_vec()), + ) + }) + } +} + +pub fn getenv(k: &OsStr) -> Option { + // environment variables with a nul byte can't be set, so their value is + // always None as well + run_with_cstr(k.as_bytes(), &|k| { + let _guard = env_read_lock(); + let v = unsafe { libc::getenv(k.as_ptr()) } as *const libc::c_char; + + if v.is_null() { + Ok(None) + } else { + // SAFETY: `v` cannot be mutated while executing this line since we've a read lock + let bytes = unsafe { CStr::from_ptr(v) }.to_bytes().to_vec(); + + Ok(Some(OsStringExt::from_vec(bytes))) + } + }) + .ok() + .flatten() +} + +pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { + run_with_cstr(k.as_bytes(), &|k| { + run_with_cstr(v.as_bytes(), &|v| { + let _guard = ENV_LOCK.write(); + cvt_env(unsafe { libc::setenv(k.as_ptr(), v.as_ptr(), 1) }).map(drop) + }) + }) +} + +pub unsafe fn unsetenv(n: &OsStr) -> io::Result<()> { + run_with_cstr(n.as_bytes(), &|nbuf| { + let _guard = ENV_LOCK.write(); + cvt_env(unsafe { libc::unsetenv(nbuf.as_ptr()) }).map(drop) + }) +} + +/// In kmclib, `setenv` and `unsetenv` don't always set `errno`, so this +/// function just returns a generic error. +fn cvt_env(t: c_int) -> io::Result { + if t == -1 { Err(io::const_error!(io::ErrorKind::Uncategorized, "failure")) } else { Ok(t) } +} diff --git a/library/std/src/sys/env/uefi.rs b/library/std/src/sys/env/uefi.rs new file mode 100644 index 000000000000..a26305acf8e0 --- /dev/null +++ b/library/std/src/sys/env/uefi.rs @@ -0,0 +1,138 @@ +use crate::ffi::{OsStr, OsString}; +use crate::{fmt, io}; + +pub struct EnvStrDebug<'a> { + iter: &'a [(OsString, OsString)], +} + +impl fmt::Debug for EnvStrDebug<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut list = f.debug_list(); + for (a, b) in self.iter { + list.entry(&(a.to_str().unwrap(), b.to_str().unwrap())); + } + list.finish() + } +} + +pub struct Env(crate::vec::IntoIter<(OsString, OsString)>); + +impl Env { + // FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. + pub fn str_debug(&self) -> impl fmt::Debug + '_ { + EnvStrDebug { iter: self.0.as_slice() } + } +} + +impl Iterator for Env { + type Item = (OsString, OsString); + + fn next(&mut self) -> Option<(OsString, OsString)> { + self.0.next() + } +} + +impl fmt::Debug for Env { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +pub fn env() -> Env { + let env = uefi_env::get_all().expect("not supported on this platform"); + Env(env.into_iter()) +} + +pub fn getenv(key: &OsStr) -> Option { + uefi_env::get(key) +} + +pub unsafe fn setenv(key: &OsStr, val: &OsStr) -> io::Result<()> { + uefi_env::set(key, val) +} + +pub unsafe fn unsetenv(key: &OsStr) -> io::Result<()> { + uefi_env::unset(key) +} + +mod uefi_env { + use crate::ffi::{OsStr, OsString}; + use crate::io; + use crate::os::uefi::ffi::OsStringExt; + use crate::ptr::NonNull; + use crate::sys::{helpers, unsupported_err}; + + pub(crate) fn get(key: &OsStr) -> Option { + let shell = helpers::open_shell()?; + let mut key_ptr = helpers::os_string_to_raw(key)?; + unsafe { get_raw(shell, key_ptr.as_mut_ptr()) } + } + + pub(crate) fn set(key: &OsStr, val: &OsStr) -> io::Result<()> { + let mut key_ptr = helpers::os_string_to_raw(key) + .ok_or(io::const_error!(io::ErrorKind::InvalidInput, "invalid key"))?; + let mut val_ptr = helpers::os_string_to_raw(val) + .ok_or(io::const_error!(io::ErrorKind::InvalidInput, "invalid value"))?; + unsafe { set_raw(key_ptr.as_mut_ptr(), val_ptr.as_mut_ptr()) } + } + + pub(crate) fn unset(key: &OsStr) -> io::Result<()> { + let mut key_ptr = helpers::os_string_to_raw(key) + .ok_or(io::const_error!(io::ErrorKind::InvalidInput, "invalid key"))?; + unsafe { set_raw(key_ptr.as_mut_ptr(), crate::ptr::null_mut()) } + } + + pub(crate) fn get_all() -> io::Result> { + let shell = helpers::open_shell().ok_or(unsupported_err())?; + + let mut vars = Vec::new(); + let val = unsafe { ((*shell.as_ptr()).get_env)(crate::ptr::null_mut()) }; + + if val.is_null() { + return Ok(vars); + } + + let mut start = 0; + + // UEFI Shell returns all keys separated by NULL. + // End of string is denoted by two NULLs + for i in 0.. { + if unsafe { *val.add(i) } == 0 { + // Two NULL signal end of string + if i == start { + break; + } + + let key = OsString::from_wide(unsafe { + crate::slice::from_raw_parts(val.add(start), i - start) + }); + // SAFETY: val.add(start) is always NULL terminated + let val = unsafe { get_raw(shell, val.add(start)) } + .ok_or(io::const_error!(io::ErrorKind::InvalidInput, "invalid value"))?; + + vars.push((key, val)); + start = i + 1; + } + } + + Ok(vars) + } + + unsafe fn get_raw( + shell: NonNull, + key_ptr: *mut r_efi::efi::Char16, + ) -> Option { + let val = unsafe { ((*shell.as_ptr()).get_env)(key_ptr) }; + helpers::os_string_from_raw(val) + } + + unsafe fn set_raw( + key_ptr: *mut r_efi::efi::Char16, + val_ptr: *mut r_efi::efi::Char16, + ) -> io::Result<()> { + let shell = helpers::open_shell().ok_or(unsupported_err())?; + let r = + unsafe { ((*shell.as_ptr()).set_env)(key_ptr, val_ptr, r_efi::efi::Boolean::FALSE) }; + if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) } + } +} diff --git a/library/std/src/sys/env/unix.rs b/library/std/src/sys/env/unix.rs new file mode 100644 index 000000000000..906a9b40112a --- /dev/null +++ b/library/std/src/sys/env/unix.rs @@ -0,0 +1,172 @@ +#![allow(unsafe_op_in_unsafe_fn)] + +use core::slice::memchr; + +use libc::c_char; + +use crate::ffi::{CStr, OsStr, OsString}; +use crate::os::unix::prelude::*; +use crate::sync::{PoisonError, RwLock}; +use crate::sys::common::small_c_string::run_with_cstr; +use crate::sys::cvt; +use crate::{fmt, io, vec}; + +pub struct Env { + iter: vec::IntoIter<(OsString, OsString)>, +} + +// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. +pub struct EnvStrDebug<'a> { + slice: &'a [(OsString, OsString)], +} + +impl fmt::Debug for EnvStrDebug<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { slice } = self; + f.debug_list() + .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap()))) + .finish() + } +} + +impl Env { + pub fn str_debug(&self) -> impl fmt::Debug + '_ { + let Self { iter } = self; + EnvStrDebug { slice: iter.as_slice() } + } +} + +impl fmt::Debug for Env { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { iter } = self; + f.debug_list().entries(iter.as_slice()).finish() + } +} + +impl !Send for Env {} +impl !Sync for Env {} + +impl Iterator for Env { + type Item = (OsString, OsString); + fn next(&mut self) -> Option<(OsString, OsString)> { + self.iter.next() + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +// Use `_NSGetEnviron` on Apple platforms. +// +// `_NSGetEnviron` is the documented alternative (see `man environ`), and has +// been available since the first versions of both macOS and iOS. +// +// Nowadays, specifically since macOS 10.8, `environ` has been exposed through +// `libdyld.dylib`, which is linked via. `libSystem.dylib`: +// +// +// So in the end, it likely doesn't really matter which option we use, but the +// performance cost of using `_NSGetEnviron` is extremely miniscule, and it +// might be ever so slightly more supported, so let's just use that. +// +// NOTE: The header where this is defined (`crt_externs.h`) was added to the +// iOS 13.0 SDK, which has been the source of a great deal of confusion in the +// past about the availability of this API. +// +// NOTE(madsmtm): Neither this nor using `environ` has been verified to not +// cause App Store rejections; if this is found to be the case, an alternative +// implementation of this is possible using `[NSProcessInfo environment]` +// - which internally uses `_NSGetEnviron` and a system-wide lock on the +// environment variables to protect against `setenv`, so using that might be +// desirable anyhow? Though it also means that we have to link to Foundation. +#[cfg(target_vendor = "apple")] +pub unsafe fn environ() -> *mut *const *const c_char { + libc::_NSGetEnviron() as *mut *const *const c_char +} + +// Use the `environ` static which is part of POSIX. +#[cfg(not(target_vendor = "apple"))] +pub unsafe fn environ() -> *mut *const *const c_char { + unsafe extern "C" { + static mut environ: *const *const c_char; + } + &raw mut environ +} + +static ENV_LOCK: RwLock<()> = RwLock::new(()); + +pub fn env_read_lock() -> impl Drop { + ENV_LOCK.read().unwrap_or_else(PoisonError::into_inner) +} + +/// Returns a vector of (variable, value) byte-vector pairs for all the +/// environment variables of the current process. +pub fn env() -> Env { + unsafe { + let _guard = env_read_lock(); + let mut environ = *environ(); + let mut result = Vec::new(); + if !environ.is_null() { + while !(*environ).is_null() { + if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) { + result.push(key_value); + } + environ = environ.add(1); + } + } + return Env { iter: result.into_iter() }; + } + + fn parse(input: &[u8]) -> Option<(OsString, OsString)> { + // Strategy (copied from glibc): Variable name and value are separated + // by an ASCII equals sign '='. Since a variable name must not be + // empty, allow variable names starting with an equals sign. Skip all + // malformed lines. + if input.is_empty() { + return None; + } + let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1); + pos.map(|p| { + ( + OsStringExt::from_vec(input[..p].to_vec()), + OsStringExt::from_vec(input[p + 1..].to_vec()), + ) + }) + } +} + +pub fn getenv(k: &OsStr) -> Option { + // environment variables with a nul byte can't be set, so their value is + // always None as well + run_with_cstr(k.as_bytes(), &|k| { + let _guard = env_read_lock(); + let v = unsafe { libc::getenv(k.as_ptr()) } as *const libc::c_char; + + if v.is_null() { + Ok(None) + } else { + // SAFETY: `v` cannot be mutated while executing this line since we've a read lock + let bytes = unsafe { CStr::from_ptr(v) }.to_bytes().to_vec(); + + Ok(Some(OsStringExt::from_vec(bytes))) + } + }) + .ok() + .flatten() +} + +pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { + run_with_cstr(k.as_bytes(), &|k| { + run_with_cstr(v.as_bytes(), &|v| { + let _guard = ENV_LOCK.write(); + cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(drop) + }) + }) +} + +pub unsafe fn unsetenv(n: &OsStr) -> io::Result<()> { + run_with_cstr(n.as_bytes(), &|nbuf| { + let _guard = ENV_LOCK.write(); + cvt(libc::unsetenv(nbuf.as_ptr())).map(drop) + }) +} diff --git a/library/std/src/sys/env/unsupported.rs b/library/std/src/sys/env/unsupported.rs new file mode 100644 index 000000000000..7ad76d8e31ca --- /dev/null +++ b/library/std/src/sys/env/unsupported.rs @@ -0,0 +1,43 @@ +use crate::ffi::{OsStr, OsString}; +use crate::{fmt, io}; + +pub struct Env(!); + +impl Env { + // FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. + pub fn str_debug(&self) -> impl fmt::Debug + '_ { + let Self(inner) = self; + match *inner {} + } +} + +impl fmt::Debug for Env { + fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self(inner) = self; + match *inner {} + } +} + +impl Iterator for Env { + type Item = (OsString, OsString); + fn next(&mut self) -> Option<(OsString, OsString)> { + let Self(inner) = self; + match *inner {} + } +} + +pub fn env() -> Env { + panic!("not supported on this platform") +} + +pub fn getenv(_: &OsStr) -> Option { + None +} + +pub unsafe fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> { + Err(io::const_error!(io::ErrorKind::Unsupported, "cannot set env vars on this platform")) +} + +pub unsafe fn unsetenv(_: &OsStr) -> io::Result<()> { + Err(io::const_error!(io::ErrorKind::Unsupported, "cannot unset env vars on this platform")) +} diff --git a/library/std/src/sys/env/wasi.rs b/library/std/src/sys/env/wasi.rs new file mode 100644 index 000000000000..6bdb2d5a547a --- /dev/null +++ b/library/std/src/sys/env/wasi.rs @@ -0,0 +1,146 @@ +use core::slice::memchr; + +use crate::ffi::{CStr, OsStr, OsString}; +use crate::os::wasi::prelude::*; +use crate::sys::common::small_c_string::run_with_cstr; +use crate::sys::pal::os::{cvt, libc}; +use crate::{fmt, io, vec}; + +pub struct Env { + iter: vec::IntoIter<(OsString, OsString)>, +} + +// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. +pub struct EnvStrDebug<'a> { + slice: &'a [(OsString, OsString)], +} + +impl fmt::Debug for EnvStrDebug<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { slice } = self; + f.debug_list() + .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap()))) + .finish() + } +} + +impl Env { + pub fn str_debug(&self) -> impl fmt::Debug + '_ { + let Self { iter } = self; + EnvStrDebug { slice: iter.as_slice() } + } +} + +impl fmt::Debug for Env { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { iter } = self; + f.debug_list().entries(iter.as_slice()).finish() + } +} + +impl !Send for Env {} +impl !Sync for Env {} + +impl Iterator for Env { + type Item = (OsString, OsString); + fn next(&mut self) -> Option<(OsString, OsString)> { + self.iter.next() + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +cfg_if::cfg_if! { + if #[cfg(target_feature = "atomics")] { + // Access to the environment must be protected by a lock in multi-threaded scenarios. + use crate::sync::{PoisonError, RwLock}; + static ENV_LOCK: RwLock<()> = RwLock::new(()); + pub fn env_read_lock() -> impl Drop { + ENV_LOCK.read().unwrap_or_else(PoisonError::into_inner) + } + pub fn env_write_lock() -> impl Drop { + ENV_LOCK.write().unwrap_or_else(PoisonError::into_inner) + } + } else { + // No need for a lock if we are single-threaded. + pub fn env_read_lock() -> impl Drop { + Box::new(()) + } + pub fn env_write_lock() -> impl Drop { + Box::new(()) + } + } +} + +pub fn env() -> Env { + unsafe { + let _guard = env_read_lock(); + + // Use `__wasilibc_get_environ` instead of `environ` here so that we + // don't require wasi-libc to eagerly initialize the environment + // variables. + let mut environ = libc::__wasilibc_get_environ(); + + let mut result = Vec::new(); + if !environ.is_null() { + while !(*environ).is_null() { + if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) { + result.push(key_value); + } + environ = environ.add(1); + } + } + return Env { iter: result.into_iter() }; + } + + // See src/libstd/sys/pal/unix/os.rs, same as that + fn parse(input: &[u8]) -> Option<(OsString, OsString)> { + if input.is_empty() { + return None; + } + let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1); + pos.map(|p| { + ( + OsStringExt::from_vec(input[..p].to_vec()), + OsStringExt::from_vec(input[p + 1..].to_vec()), + ) + }) + } +} + +pub fn getenv(k: &OsStr) -> Option { + // environment variables with a nul byte can't be set, so their value is + // always None as well + run_with_cstr(k.as_bytes(), &|k| { + let _guard = env_read_lock(); + let v = unsafe { libc::getenv(k.as_ptr()) } as *const libc::c_char; + + if v.is_null() { + Ok(None) + } else { + // SAFETY: `v` cannot be mutated while executing this line since we've a read lock + let bytes = unsafe { CStr::from_ptr(v) }.to_bytes().to_vec(); + + Ok(Some(OsStringExt::from_vec(bytes))) + } + }) + .ok() + .flatten() +} + +pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { + run_with_cstr(k.as_bytes(), &|k| { + run_with_cstr(v.as_bytes(), &|v| unsafe { + let _guard = env_write_lock(); + cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(drop) + }) + }) +} + +pub unsafe fn unsetenv(n: &OsStr) -> io::Result<()> { + run_with_cstr(n.as_bytes(), &|nbuf| unsafe { + let _guard = env_write_lock(); + cvt(libc::unsetenv(nbuf.as_ptr())).map(drop) + }) +} diff --git a/library/std/src/sys/env/windows.rs b/library/std/src/sys/env/windows.rs new file mode 100644 index 000000000000..3c4d4a84cfd6 --- /dev/null +++ b/library/std/src/sys/env/windows.rs @@ -0,0 +1,133 @@ +use crate::ffi::{OsStr, OsString}; +use crate::os::windows::prelude::*; +use crate::sys::pal::{c, cvt, fill_utf16_buf, to_u16s}; +use crate::{fmt, io, ptr, slice}; + +pub struct Env { + base: *mut c::WCHAR, + iter: EnvIterator, +} + +// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. +pub struct EnvStrDebug<'a> { + iter: &'a EnvIterator, +} + +impl fmt::Debug for EnvStrDebug<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { iter } = self; + let iter: EnvIterator = (*iter).clone(); + let mut list = f.debug_list(); + for (a, b) in iter { + list.entry(&(a.to_str().unwrap(), b.to_str().unwrap())); + } + list.finish() + } +} + +impl Env { + pub fn str_debug(&self) -> impl fmt::Debug + '_ { + let Self { base: _, iter } = self; + EnvStrDebug { iter } + } +} + +impl fmt::Debug for Env { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { base: _, iter } = self; + f.debug_list().entries(iter.clone()).finish() + } +} + +impl Iterator for Env { + type Item = (OsString, OsString); + + fn next(&mut self) -> Option<(OsString, OsString)> { + let Self { base: _, iter } = self; + iter.next() + } +} + +#[derive(Clone)] +struct EnvIterator(*mut c::WCHAR); + +impl Iterator for EnvIterator { + type Item = (OsString, OsString); + + fn next(&mut self) -> Option<(OsString, OsString)> { + let Self(cur) = self; + loop { + unsafe { + if **cur == 0 { + return None; + } + let p = *cur as *const u16; + let mut len = 0; + while *p.add(len) != 0 { + len += 1; + } + let s = slice::from_raw_parts(p, len); + *cur = cur.add(len + 1); + + // Windows allows environment variables to start with an equals + // symbol (in any other position, this is the separator between + // variable name and value). Since`s` has at least length 1 at + // this point (because the empty string terminates the array of + // environment variables), we can safely slice. + let pos = match s[1..].iter().position(|&u| u == b'=' as u16).map(|p| p + 1) { + Some(p) => p, + None => continue, + }; + return Some(( + OsStringExt::from_wide(&s[..pos]), + OsStringExt::from_wide(&s[pos + 1..]), + )); + } + } + } +} + +impl Drop for Env { + fn drop(&mut self) { + unsafe { + c::FreeEnvironmentStringsW(self.base); + } + } +} + +pub fn env() -> Env { + unsafe { + let ch = c::GetEnvironmentStringsW(); + if ch.is_null() { + panic!("failure getting env string from OS: {}", io::Error::last_os_error()); + } + Env { base: ch, iter: EnvIterator(ch) } + } +} + +pub fn getenv(k: &OsStr) -> Option { + let k = to_u16s(k).ok()?; + fill_utf16_buf( + |buf, sz| unsafe { c::GetEnvironmentVariableW(k.as_ptr(), buf, sz) }, + OsStringExt::from_wide, + ) + .ok() +} + +pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { + // SAFETY: We ensure that k and v are null-terminated wide strings. + unsafe { + let k = to_u16s(k)?; + let v = to_u16s(v)?; + + cvt(c::SetEnvironmentVariableW(k.as_ptr(), v.as_ptr())).map(drop) + } +} + +pub unsafe fn unsetenv(n: &OsStr) -> io::Result<()> { + // SAFETY: We ensure that v is a null-terminated wide strings. + unsafe { + let v = to_u16s(n)?; + cvt(c::SetEnvironmentVariableW(v.as_ptr(), ptr::null())).map(drop) + } +} diff --git a/library/std/src/sys/env/xous.rs b/library/std/src/sys/env/xous.rs new file mode 100644 index 000000000000..d5b8a1c7fb45 --- /dev/null +++ b/library/std/src/sys/env/xous.rs @@ -0,0 +1,99 @@ +use crate::collections::HashMap; +use crate::ffi::{OsStr, OsString}; +use crate::sync::atomic::{AtomicUsize, Ordering}; +use crate::sync::{Mutex, Once}; +use crate::sys::pal::os::{get_application_parameters, params}; +use crate::{fmt, io, vec}; + +static ENV: AtomicUsize = AtomicUsize::new(0); +static ENV_INIT: Once = Once::new(); +type EnvStore = Mutex>; + +fn get_env_store() -> &'static EnvStore { + ENV_INIT.call_once(|| { + let env_store = EnvStore::default(); + if let Some(params) = get_application_parameters() { + for param in params { + if let Ok(envs) = params::EnvironmentBlock::try_from(¶m) { + let mut env_store = env_store.lock().unwrap(); + for env in envs { + env_store.insert(env.key.into(), env.value.into()); + } + break; + } + } + } + ENV.store(Box::into_raw(Box::new(env_store)) as _, Ordering::Relaxed) + }); + unsafe { &*core::ptr::with_exposed_provenance::(ENV.load(Ordering::Relaxed)) } +} + +pub struct Env { + iter: vec::IntoIter<(OsString, OsString)>, +} + +// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. +pub struct EnvStrDebug<'a> { + slice: &'a [(OsString, OsString)], +} + +impl fmt::Debug for EnvStrDebug<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { slice } = self; + f.debug_list() + .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap()))) + .finish() + } +} + +impl Env { + // FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. + pub fn str_debug(&self) -> impl fmt::Debug + '_ { + let Self { iter } = self; + EnvStrDebug { slice: iter.as_slice() } + } +} + +impl fmt::Debug for Env { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { iter } = self; + f.debug_list().entries(iter.as_slice()).finish() + } +} + +impl !Send for Env {} +impl !Sync for Env {} + +impl Iterator for Env { + type Item = (OsString, OsString); + fn next(&mut self) -> Option<(OsString, OsString)> { + self.iter.next() + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +pub fn env() -> Env { + let clone_to_vec = |map: &HashMap| -> Vec<_> { + map.iter().map(|(k, v)| (k.clone(), v.clone())).collect() + }; + + let iter = clone_to_vec(&*get_env_store().lock().unwrap()).into_iter(); + Env { iter } +} + +pub fn getenv(k: &OsStr) -> Option { + get_env_store().lock().unwrap().get(k).cloned() +} + +pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { + let (k, v) = (k.to_owned(), v.to_owned()); + get_env_store().lock().unwrap().insert(k, v); + Ok(()) +} + +pub unsafe fn unsetenv(k: &OsStr) -> io::Result<()> { + get_env_store().lock().unwrap().remove(k); + Ok(()) +} diff --git a/library/std/src/sys/env/zkvm.rs b/library/std/src/sys/env/zkvm.rs new file mode 100644 index 000000000000..8d0bf7a198ed --- /dev/null +++ b/library/std/src/sys/env/zkvm.rs @@ -0,0 +1,63 @@ +use crate::ffi::{OsStr, OsString}; +use crate::sys::os_str; +use crate::sys::pal::{WORD_SIZE, abi}; +use crate::sys_common::FromInner; +use crate::{fmt, io}; + +pub struct Env(!); + +impl Iterator for Env { + type Item = (OsString, OsString); + fn next(&mut self) -> Option<(OsString, OsString)> { + self.0 + } +} + +pub fn env() -> Env { + panic!("not supported on this platform") +} + +impl Env { + pub fn str_debug(&self) -> impl fmt::Debug + '_ { + let Self(inner) = self; + match *inner {} + } +} + +impl fmt::Debug for Env { + fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self(inner) = self; + match *inner {} + } +} + +pub fn getenv(varname: &OsStr) -> Option { + let varname = varname.as_encoded_bytes(); + let nbytes = + unsafe { abi::sys_getenv(crate::ptr::null_mut(), 0, varname.as_ptr(), varname.len()) }; + if nbytes == usize::MAX { + return None; + } + + let nwords = (nbytes + WORD_SIZE - 1) / WORD_SIZE; + let words = unsafe { abi::sys_alloc_words(nwords) }; + + let nbytes2 = unsafe { abi::sys_getenv(words, nwords, varname.as_ptr(), varname.len()) }; + debug_assert_eq!(nbytes, nbytes2); + + // Convert to OsString. + // + // FIXME: We can probably get rid of the extra copy here if we + // reimplement "os_str" instead of just using the generic unix + // "os_str". + let u8s: &[u8] = unsafe { crate::slice::from_raw_parts(words.cast() as *const u8, nbytes) }; + Some(OsString::from_inner(os_str::Buf { inner: u8s.to_vec() })) +} + +pub unsafe fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> { + Err(io::const_error!(io::ErrorKind::Unsupported, "cannot set env vars on this platform")) +} + +pub unsafe fn unsetenv(_: &OsStr) -> io::Result<()> { + Err(io::const_error!(io::ErrorKind::Unsupported, "cannot unset env vars on this platform")) +} diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index e7b631999e0d..f9a02b522e5e 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -12,6 +12,7 @@ pub mod anonymous_pipe; pub mod args; pub mod backtrace; pub mod cmath; +pub mod env; pub mod env_consts; pub mod exit_guard; pub mod fd; diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs index 70636760a83b..ea636938d703 100644 --- a/library/std/src/sys/pal/hermit/mod.rs +++ b/library/std/src/sys/pal/hermit/mod.rs @@ -16,7 +16,10 @@ #![deny(unsafe_op_in_unsafe_fn)] #![allow(missing_docs, nonstandard_style)] +use crate::io::ErrorKind; +use crate::os::hermit::hermit_abi; use crate::os::raw::c_char; +use crate::sys::env; pub mod futex; pub mod os; @@ -25,9 +28,6 @@ pub mod pipe; pub mod thread; pub mod time; -use crate::io::ErrorKind; -use crate::os::hermit::hermit_abi; - pub fn unsupported() -> crate::io::Result { Err(unsupported_err()) } @@ -76,7 +76,7 @@ pub unsafe extern "C" fn runtime_entry( } // initialize environment - os::init_environment(env); + env::init(env); let result = unsafe { main(argc as isize, argv) }; diff --git a/library/std/src/sys/pal/hermit/os.rs b/library/std/src/sys/pal/hermit/os.rs index 791cdb1e57e7..a998c3165e52 100644 --- a/library/std/src/sys/pal/hermit/os.rs +++ b/library/std/src/sys/pal/hermit/os.rs @@ -1,15 +1,10 @@ -use core::slice::memchr; - use super::hermit_abi; -use crate::collections::HashMap; use crate::error::Error as StdError; -use crate::ffi::{CStr, OsStr, OsString, c_char}; +use crate::ffi::{OsStr, OsString}; use crate::marker::PhantomData; -use crate::os::hermit::ffi::OsStringExt; use crate::path::{self, PathBuf}; -use crate::sync::Mutex; use crate::sys::unsupported; -use crate::{fmt, io, str, vec}; +use crate::{fmt, io, str}; pub fn errno() -> i32 { unsafe { hermit_abi::get_errno() } @@ -68,115 +63,6 @@ pub fn current_exe() -> io::Result { unsupported() } -static ENV: Mutex>> = Mutex::new(None); - -pub fn init_environment(env: *const *const c_char) { - let mut guard = ENV.lock().unwrap(); - let map = guard.insert(HashMap::new()); - - if env.is_null() { - return; - } - - unsafe { - let mut environ = env; - while !(*environ).is_null() { - if let Some((key, value)) = parse(CStr::from_ptr(*environ).to_bytes()) { - map.insert(key, value); - } - environ = environ.add(1); - } - } - - fn parse(input: &[u8]) -> Option<(OsString, OsString)> { - // Strategy (copied from glibc): Variable name and value are separated - // by an ASCII equals sign '='. Since a variable name must not be - // empty, allow variable names starting with an equals sign. Skip all - // malformed lines. - if input.is_empty() { - return None; - } - let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1); - pos.map(|p| { - ( - OsStringExt::from_vec(input[..p].to_vec()), - OsStringExt::from_vec(input[p + 1..].to_vec()), - ) - }) - } -} - -pub struct Env { - iter: vec::IntoIter<(OsString, OsString)>, -} - -// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. -pub struct EnvStrDebug<'a> { - slice: &'a [(OsString, OsString)], -} - -impl fmt::Debug for EnvStrDebug<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { slice } = self; - f.debug_list() - .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap()))) - .finish() - } -} - -impl Env { - pub fn str_debug(&self) -> impl fmt::Debug + '_ { - let Self { iter } = self; - EnvStrDebug { slice: iter.as_slice() } - } -} - -impl fmt::Debug for Env { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { iter } = self; - f.debug_list().entries(iter.as_slice()).finish() - } -} - -impl !Send for Env {} -impl !Sync for Env {} - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -/// Returns a vector of (variable, value) byte-vector pairs for all the -/// environment variables of the current process. -pub fn env() -> Env { - let guard = ENV.lock().unwrap(); - let env = guard.as_ref().unwrap(); - - let result = env.iter().map(|(key, value)| (key.clone(), value.clone())).collect::>(); - - Env { iter: result.into_iter() } -} - -pub fn getenv(k: &OsStr) -> Option { - ENV.lock().unwrap().as_ref().unwrap().get(k).cloned() -} - -pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { - let (k, v) = (k.to_owned(), v.to_owned()); - ENV.lock().unwrap().as_mut().unwrap().insert(k, v); - Ok(()) -} - -pub unsafe fn unsetenv(k: &OsStr) -> io::Result<()> { - ENV.lock().unwrap().as_mut().unwrap().remove(k); - Ok(()) -} - pub fn temp_dir() -> PathBuf { PathBuf::from("/tmp") } diff --git a/library/std/src/sys/pal/sgx/os.rs b/library/std/src/sys/pal/sgx/os.rs index 010634cf3106..70f838679c9c 100644 --- a/library/std/src/sys/pal/sgx/os.rs +++ b/library/std/src/sys/pal/sgx/os.rs @@ -1,14 +1,11 @@ use fortanix_sgx_abi::{Error, RESULT_SUCCESS}; -use crate::collections::HashMap; use crate::error::Error as StdError; use crate::ffi::{OsStr, OsString}; use crate::marker::PhantomData; use crate::path::{self, PathBuf}; -use crate::sync::atomic::{AtomicUsize, Ordering}; -use crate::sync::{Mutex, Once}; use crate::sys::{decode_error_kind, sgx_ineffective, unsupported}; -use crate::{fmt, io, str, vec}; +use crate::{fmt, io, str}; pub fn errno() -> i32 { RESULT_SUCCESS @@ -73,101 +70,6 @@ pub fn current_exe() -> io::Result { unsupported() } -// Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests -#[cfg_attr(test, linkage = "available_externally")] -#[unsafe(export_name = "_ZN16__rust_internals3std3sys3pal3sgx2os3ENVE")] -static ENV: AtomicUsize = AtomicUsize::new(0); -// Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests -#[cfg_attr(test, linkage = "available_externally")] -#[unsafe(export_name = "_ZN16__rust_internals3std3sys3pal3sgx2os8ENV_INITE")] -static ENV_INIT: Once = Once::new(); -type EnvStore = Mutex>; - -fn get_env_store() -> Option<&'static EnvStore> { - unsafe { (ENV.load(Ordering::Relaxed) as *const EnvStore).as_ref() } -} - -fn create_env_store() -> &'static EnvStore { - ENV_INIT.call_once(|| { - ENV.store(Box::into_raw(Box::new(EnvStore::default())) as _, Ordering::Relaxed) - }); - unsafe { &*(ENV.load(Ordering::Relaxed) as *const EnvStore) } -} - -pub struct Env { - iter: vec::IntoIter<(OsString, OsString)>, -} - -// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. -pub struct EnvStrDebug<'a> { - slice: &'a [(OsString, OsString)], -} - -impl fmt::Debug for EnvStrDebug<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { slice } = self; - f.debug_list() - .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap()))) - .finish() - } -} - -impl Env { - pub fn str_debug(&self) -> impl fmt::Debug + '_ { - let Self { iter } = self; - EnvStrDebug { slice: iter.as_slice() } - } -} - -impl fmt::Debug for Env { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { iter } = self; - f.debug_list().entries(iter.as_slice()).finish() - } -} - -impl !Send for Env {} -impl !Sync for Env {} - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -pub fn env() -> Env { - let clone_to_vec = |map: &HashMap| -> Vec<_> { - map.iter().map(|(k, v)| (k.clone(), v.clone())).collect() - }; - - let iter = get_env_store() - .map(|env| clone_to_vec(&env.lock().unwrap())) - .unwrap_or_default() - .into_iter(); - Env { iter } -} - -pub fn getenv(k: &OsStr) -> Option { - get_env_store().and_then(|s| s.lock().unwrap().get(k).cloned()) -} - -pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { - let (k, v) = (k.to_owned(), v.to_owned()); - create_env_store().lock().unwrap().insert(k, v); - Ok(()) -} - -pub unsafe fn unsetenv(k: &OsStr) -> io::Result<()> { - if let Some(env) = get_env_store() { - env.lock().unwrap().remove(k); - } - Ok(()) -} - pub fn temp_dir() -> PathBuf { panic!("no filesystem in SGX") } diff --git a/library/std/src/sys/pal/solid/os.rs b/library/std/src/sys/pal/solid/os.rs index e3b2e0aa50f4..8f5976b0592e 100644 --- a/library/std/src/sys/pal/solid/os.rs +++ b/library/std/src/sys/pal/solid/os.rs @@ -1,14 +1,8 @@ -use core::slice::memchr; - use super::{error, itron, unsupported}; use crate::error::Error as StdError; -use crate::ffi::{CStr, OsStr, OsString}; -use crate::os::raw::{c_char, c_int}; -use crate::os::solid::ffi::{OsStrExt, OsStringExt}; +use crate::ffi::{OsStr, OsString}; use crate::path::{self, PathBuf}; -use crate::sync::{PoisonError, RwLock}; -use crate::sys::common::small_c_string::run_with_cstr; -use crate::{fmt, io, vec}; +use crate::{fmt, io}; // `solid` directly maps `errno`s to μITRON error codes. impl itron::error::ItronError { @@ -75,138 +69,6 @@ pub fn current_exe() -> io::Result { unsupported() } -static ENV_LOCK: RwLock<()> = RwLock::new(()); - -pub fn env_read_lock() -> impl Drop { - ENV_LOCK.read().unwrap_or_else(PoisonError::into_inner) -} - -pub struct Env { - iter: vec::IntoIter<(OsString, OsString)>, -} - -// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. -pub struct EnvStrDebug<'a> { - slice: &'a [(OsString, OsString)], -} - -impl fmt::Debug for EnvStrDebug<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { slice } = self; - f.debug_list() - .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap()))) - .finish() - } -} - -impl Env { - pub fn str_debug(&self) -> impl fmt::Debug + '_ { - let Self { iter } = self; - EnvStrDebug { slice: iter.as_slice() } - } -} - -impl fmt::Debug for Env { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { iter } = self; - f.debug_list().entries(iter.as_slice()).finish() - } -} - -impl !Send for Env {} -impl !Sync for Env {} - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -/// Returns a vector of (variable, value) byte-vector pairs for all the -/// environment variables of the current process. -pub fn env() -> Env { - unsafe extern "C" { - static mut environ: *const *const c_char; - } - - unsafe { - let _guard = env_read_lock(); - let mut result = Vec::new(); - if !environ.is_null() { - while !(*environ).is_null() { - if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) { - result.push(key_value); - } - environ = environ.add(1); - } - } - return Env { iter: result.into_iter() }; - } - - fn parse(input: &[u8]) -> Option<(OsString, OsString)> { - // Strategy (copied from glibc): Variable name and value are separated - // by an ASCII equals sign '='. Since a variable name must not be - // empty, allow variable names starting with an equals sign. Skip all - // malformed lines. - if input.is_empty() { - return None; - } - let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1); - pos.map(|p| { - ( - OsStringExt::from_vec(input[..p].to_vec()), - OsStringExt::from_vec(input[p + 1..].to_vec()), - ) - }) - } -} - -pub fn getenv(k: &OsStr) -> Option { - // environment variables with a nul byte can't be set, so their value is - // always None as well - run_with_cstr(k.as_bytes(), &|k| { - let _guard = env_read_lock(); - let v = unsafe { libc::getenv(k.as_ptr()) } as *const libc::c_char; - - if v.is_null() { - Ok(None) - } else { - // SAFETY: `v` cannot be mutated while executing this line since we've a read lock - let bytes = unsafe { CStr::from_ptr(v) }.to_bytes().to_vec(); - - Ok(Some(OsStringExt::from_vec(bytes))) - } - }) - .ok() - .flatten() -} - -pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { - run_with_cstr(k.as_bytes(), &|k| { - run_with_cstr(v.as_bytes(), &|v| { - let _guard = ENV_LOCK.write(); - cvt_env(unsafe { libc::setenv(k.as_ptr(), v.as_ptr(), 1) }).map(drop) - }) - }) -} - -pub unsafe fn unsetenv(n: &OsStr) -> io::Result<()> { - run_with_cstr(n.as_bytes(), &|nbuf| { - let _guard = ENV_LOCK.write(); - cvt_env(unsafe { libc::unsetenv(nbuf.as_ptr()) }).map(drop) - }) -} - -/// In kmclib, `setenv` and `unsetenv` don't always set `errno`, so this -/// function just returns a generic error. -fn cvt_env(t: c_int) -> io::Result { - if t == -1 { Err(io::const_error!(io::ErrorKind::Uncategorized, "failure")) } else { Ok(t) } -} - pub fn temp_dir() -> PathBuf { panic!("no standard temporary directory on this platform") } diff --git a/library/std/src/sys/pal/teeos/os.rs b/library/std/src/sys/pal/teeos/os.rs index bf6945811ab0..03f3c72b0229 100644 --- a/library/std/src/sys/pal/teeos/os.rs +++ b/library/std/src/sys/pal/teeos/os.rs @@ -73,47 +73,6 @@ pub fn current_exe() -> io::Result { unsupported() } -pub struct Env(!); - -impl Env { - // FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. - pub fn str_debug(&self) -> impl fmt::Debug + '_ { - let Self(inner) = self; - match *inner {} - } -} - -impl fmt::Debug for Env { - fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self(inner) = self; - match *inner {} - } -} - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - let Self(inner) = self; - match *inner {} - } -} - -pub fn env() -> Env { - panic!("not supported on this platform") -} - -pub fn getenv(_: &OsStr) -> Option { - None -} - -pub unsafe fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> { - Err(io::const_error!(io::ErrorKind::Unsupported, "cannot set env vars on this platform")) -} - -pub unsafe fn unsetenv(_: &OsStr) -> io::Result<()> { - Err(io::const_error!(io::ErrorKind::Unsupported, "cannot unset env vars on this platform")) -} - pub fn temp_dir() -> PathBuf { panic!("no filesystem on this platform") } diff --git a/library/std/src/sys/pal/uefi/os.rs b/library/std/src/sys/pal/uefi/os.rs index d26d61890c19..bfd4dc81cb44 100644 --- a/library/std/src/sys/pal/uefi/os.rs +++ b/library/std/src/sys/pal/uefi/os.rs @@ -131,60 +131,6 @@ pub fn current_exe() -> io::Result { helpers::device_path_to_text(protocol).map(PathBuf::from) } -pub struct EnvStrDebug<'a> { - iter: &'a [(OsString, OsString)], -} - -impl fmt::Debug for EnvStrDebug<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut list = f.debug_list(); - for (a, b) in self.iter { - list.entry(&(a.to_str().unwrap(), b.to_str().unwrap())); - } - list.finish() - } -} - -pub struct Env(crate::vec::IntoIter<(OsString, OsString)>); - -impl Env { - // FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. - pub fn str_debug(&self) -> impl fmt::Debug + '_ { - EnvStrDebug { iter: self.0.as_slice() } - } -} - -impl Iterator for Env { - type Item = (OsString, OsString); - - fn next(&mut self) -> Option<(OsString, OsString)> { - self.0.next() - } -} - -impl fmt::Debug for Env { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -pub fn env() -> Env { - let env = uefi_env::get_all().expect("not supported on this platform"); - Env(env.into_iter()) -} - -pub fn getenv(key: &OsStr) -> Option { - uefi_env::get(key) -} - -pub unsafe fn setenv(key: &OsStr, val: &OsStr) -> io::Result<()> { - uefi_env::set(key, val) -} - -pub unsafe fn unsetenv(key: &OsStr) -> io::Result<()> { - uefi_env::unset(key) -} - pub fn temp_dir() -> PathBuf { panic!("no filesystem on this platform") } @@ -213,85 +159,3 @@ pub fn exit(code: i32) -> ! { pub fn getpid() -> u32 { panic!("no pids on this platform") } - -mod uefi_env { - use crate::ffi::{OsStr, OsString}; - use crate::io; - use crate::os::uefi::ffi::OsStringExt; - use crate::ptr::NonNull; - use crate::sys::{helpers, unsupported_err}; - - pub(crate) fn get(key: &OsStr) -> Option { - let shell = helpers::open_shell()?; - let mut key_ptr = helpers::os_string_to_raw(key)?; - unsafe { get_raw(shell, key_ptr.as_mut_ptr()) } - } - - pub(crate) fn set(key: &OsStr, val: &OsStr) -> io::Result<()> { - let mut key_ptr = helpers::os_string_to_raw(key) - .ok_or(io::const_error!(io::ErrorKind::InvalidInput, "invalid key"))?; - let mut val_ptr = helpers::os_string_to_raw(val) - .ok_or(io::const_error!(io::ErrorKind::InvalidInput, "invalid value"))?; - unsafe { set_raw(key_ptr.as_mut_ptr(), val_ptr.as_mut_ptr()) } - } - - pub(crate) fn unset(key: &OsStr) -> io::Result<()> { - let mut key_ptr = helpers::os_string_to_raw(key) - .ok_or(io::const_error!(io::ErrorKind::InvalidInput, "invalid key"))?; - unsafe { set_raw(key_ptr.as_mut_ptr(), crate::ptr::null_mut()) } - } - - pub(crate) fn get_all() -> io::Result> { - let shell = helpers::open_shell().ok_or(unsupported_err())?; - - let mut vars = Vec::new(); - let val = unsafe { ((*shell.as_ptr()).get_env)(crate::ptr::null_mut()) }; - - if val.is_null() { - return Ok(vars); - } - - let mut start = 0; - - // UEFI Shell returns all keys separated by NULL. - // End of string is denoted by two NULLs - for i in 0.. { - if unsafe { *val.add(i) } == 0 { - // Two NULL signal end of string - if i == start { - break; - } - - let key = OsString::from_wide(unsafe { - crate::slice::from_raw_parts(val.add(start), i - start) - }); - // SAFETY: val.add(start) is always NULL terminated - let val = unsafe { get_raw(shell, val.add(start)) } - .ok_or(io::const_error!(io::ErrorKind::InvalidInput, "invalid value"))?; - - vars.push((key, val)); - start = i + 1; - } - } - - Ok(vars) - } - - unsafe fn get_raw( - shell: NonNull, - key_ptr: *mut r_efi::efi::Char16, - ) -> Option { - let val = unsafe { ((*shell.as_ptr()).get_env)(key_ptr) }; - helpers::os_string_from_raw(val) - } - - unsafe fn set_raw( - key_ptr: *mut r_efi::efi::Char16, - val_ptr: *mut r_efi::efi::Char16, - ) -> io::Result<()> { - let shell = helpers::open_shell().ok_or(unsupported_err())?; - let r = - unsafe { ((*shell.as_ptr()).set_env)(key_ptr, val_ptr, r_efi::efi::Boolean::FALSE) }; - if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) } - } -} diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index f47421c67051..4883303b88e2 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -5,20 +5,15 @@ #[cfg(test)] mod tests; -use core::slice::memchr; - use libc::{c_char, c_int, c_void}; use crate::error::Error as StdError; -use crate::ffi::{CStr, CString, OsStr, OsString}; +use crate::ffi::{CStr, OsStr, OsString}; use crate::os::unix::prelude::*; use crate::path::{self, PathBuf}; -use crate::sync::{PoisonError, RwLock}; -use crate::sys::common::small_c_string::{run_path_with_cstr, run_with_cstr}; -#[cfg(all(target_env = "gnu", not(target_os = "vxworks")))] -use crate::sys::weak::weak; -use crate::sys::{cvt, fd}; -use crate::{fmt, io, iter, mem, ptr, slice, str, vec}; +use crate::sys::common::small_c_string::run_path_with_cstr; +use crate::sys::cvt; +use crate::{fmt, io, iter, mem, ptr, slice, str}; const TMPBUF_SZ: usize = 128; @@ -552,166 +547,6 @@ pub fn current_exe() -> io::Result { if !path.is_absolute() { getcwd().map(|cwd| cwd.join(path)) } else { Ok(path) } } -pub struct Env { - iter: vec::IntoIter<(OsString, OsString)>, -} - -// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. -pub struct EnvStrDebug<'a> { - slice: &'a [(OsString, OsString)], -} - -impl fmt::Debug for EnvStrDebug<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { slice } = self; - f.debug_list() - .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap()))) - .finish() - } -} - -impl Env { - pub fn str_debug(&self) -> impl fmt::Debug + '_ { - let Self { iter } = self; - EnvStrDebug { slice: iter.as_slice() } - } -} - -impl fmt::Debug for Env { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { iter } = self; - f.debug_list().entries(iter.as_slice()).finish() - } -} - -impl !Send for Env {} -impl !Sync for Env {} - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -// Use `_NSGetEnviron` on Apple platforms. -// -// `_NSGetEnviron` is the documented alternative (see `man environ`), and has -// been available since the first versions of both macOS and iOS. -// -// Nowadays, specifically since macOS 10.8, `environ` has been exposed through -// `libdyld.dylib`, which is linked via. `libSystem.dylib`: -// -// -// So in the end, it likely doesn't really matter which option we use, but the -// performance cost of using `_NSGetEnviron` is extremely miniscule, and it -// might be ever so slightly more supported, so let's just use that. -// -// NOTE: The header where this is defined (`crt_externs.h`) was added to the -// iOS 13.0 SDK, which has been the source of a great deal of confusion in the -// past about the availability of this API. -// -// NOTE(madsmtm): Neither this nor using `environ` has been verified to not -// cause App Store rejections; if this is found to be the case, an alternative -// implementation of this is possible using `[NSProcessInfo environment]` -// - which internally uses `_NSGetEnviron` and a system-wide lock on the -// environment variables to protect against `setenv`, so using that might be -// desirable anyhow? Though it also means that we have to link to Foundation. -#[cfg(target_vendor = "apple")] -pub unsafe fn environ() -> *mut *const *const c_char { - libc::_NSGetEnviron() as *mut *const *const c_char -} - -// Use the `environ` static which is part of POSIX. -#[cfg(not(target_vendor = "apple"))] -pub unsafe fn environ() -> *mut *const *const c_char { - unsafe extern "C" { - static mut environ: *const *const c_char; - } - &raw mut environ -} - -static ENV_LOCK: RwLock<()> = RwLock::new(()); - -pub fn env_read_lock() -> impl Drop { - ENV_LOCK.read().unwrap_or_else(PoisonError::into_inner) -} - -/// Returns a vector of (variable, value) byte-vector pairs for all the -/// environment variables of the current process. -pub fn env() -> Env { - unsafe { - let _guard = env_read_lock(); - let mut environ = *environ(); - let mut result = Vec::new(); - if !environ.is_null() { - while !(*environ).is_null() { - if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) { - result.push(key_value); - } - environ = environ.add(1); - } - } - return Env { iter: result.into_iter() }; - } - - fn parse(input: &[u8]) -> Option<(OsString, OsString)> { - // Strategy (copied from glibc): Variable name and value are separated - // by an ASCII equals sign '='. Since a variable name must not be - // empty, allow variable names starting with an equals sign. Skip all - // malformed lines. - if input.is_empty() { - return None; - } - let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1); - pos.map(|p| { - ( - OsStringExt::from_vec(input[..p].to_vec()), - OsStringExt::from_vec(input[p + 1..].to_vec()), - ) - }) - } -} - -pub fn getenv(k: &OsStr) -> Option { - // environment variables with a nul byte can't be set, so their value is - // always None as well - run_with_cstr(k.as_bytes(), &|k| { - let _guard = env_read_lock(); - let v = unsafe { libc::getenv(k.as_ptr()) } as *const libc::c_char; - - if v.is_null() { - Ok(None) - } else { - // SAFETY: `v` cannot be mutated while executing this line since we've a read lock - let bytes = unsafe { CStr::from_ptr(v) }.to_bytes().to_vec(); - - Ok(Some(OsStringExt::from_vec(bytes))) - } - }) - .ok() - .flatten() -} - -pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { - run_with_cstr(k.as_bytes(), &|k| { - run_with_cstr(v.as_bytes(), &|v| { - let _guard = ENV_LOCK.write(); - cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(drop) - }) - }) -} - -pub unsafe fn unsetenv(n: &OsStr) -> io::Result<()> { - run_with_cstr(n.as_bytes(), &|nbuf| { - let _guard = ENV_LOCK.write(); - cvt(libc::unsetenv(nbuf.as_ptr())).map(drop) - }) -} - #[cfg(not(target_os = "espidf"))] pub fn page_size() -> usize { unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize } diff --git a/library/std/src/sys/pal/unsupported/os.rs b/library/std/src/sys/pal/unsupported/os.rs index 48de4312885f..a8ef97ecf67a 100644 --- a/library/std/src/sys/pal/unsupported/os.rs +++ b/library/std/src/sys/pal/unsupported/os.rs @@ -62,47 +62,6 @@ pub fn current_exe() -> io::Result { unsupported() } -pub struct Env(!); - -impl Env { - // FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. - pub fn str_debug(&self) -> impl fmt::Debug + '_ { - let Self(inner) = self; - match *inner {} - } -} - -impl fmt::Debug for Env { - fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self(inner) = self; - match *inner {} - } -} - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - let Self(inner) = self; - match *inner {} - } -} - -pub fn env() -> Env { - panic!("not supported on this platform") -} - -pub fn getenv(_: &OsStr) -> Option { - None -} - -pub unsafe fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> { - Err(io::const_error!(io::ErrorKind::Unsupported, "cannot set env vars on this platform")) -} - -pub unsafe fn unsetenv(_: &OsStr) -> io::Result<()> { - Err(io::const_error!(io::ErrorKind::Unsupported, "cannot unset env vars on this platform")) -} - pub fn temp_dir() -> PathBuf { panic!("no filesystem on this platform") } diff --git a/library/std/src/sys/pal/wasi/os.rs b/library/std/src/sys/pal/wasi/os.rs index ba2b65a1f40d..672cf70d1a5b 100644 --- a/library/std/src/sys/pal/wasi/os.rs +++ b/library/std/src/sys/pal/wasi/os.rs @@ -1,19 +1,16 @@ #![forbid(unsafe_op_in_unsafe_fn)] -use core::slice::memchr; - use crate::error::Error as StdError; use crate::ffi::{CStr, OsStr, OsString}; use crate::marker::PhantomData; -use crate::ops::Drop; use crate::os::wasi::prelude::*; use crate::path::{self, PathBuf}; -use crate::sys::common::small_c_string::{run_path_with_cstr, run_with_cstr}; +use crate::sys::common::small_c_string::run_path_with_cstr; use crate::sys::unsupported; -use crate::{fmt, io, str, vec}; +use crate::{fmt, io, str}; // Add a few symbols not in upstream `libc` just yet. -mod libc { +pub mod libc { pub use libc::*; unsafe extern "C" { @@ -23,28 +20,6 @@ mod libc { } } -cfg_if::cfg_if! { - if #[cfg(target_feature = "atomics")] { - // Access to the environment must be protected by a lock in multi-threaded scenarios. - use crate::sync::{PoisonError, RwLock}; - static ENV_LOCK: RwLock<()> = RwLock::new(()); - pub fn env_read_lock() -> impl Drop { - ENV_LOCK.read().unwrap_or_else(PoisonError::into_inner) - } - pub fn env_write_lock() -> impl Drop { - ENV_LOCK.write().unwrap_or_else(PoisonError::into_inner) - } - } else { - // No need for a lock if we are single-threaded. - pub fn env_read_lock() -> impl Drop { - Box::new(()) - } - pub fn env_write_lock() -> impl Drop { - Box::new(()) - } - } -} - pub fn errno() -> i32 { unsafe extern "C" { #[thread_local] @@ -141,123 +116,6 @@ pub fn current_exe() -> io::Result { unsupported() } -pub struct Env { - iter: vec::IntoIter<(OsString, OsString)>, -} - -// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. -pub struct EnvStrDebug<'a> { - slice: &'a [(OsString, OsString)], -} - -impl fmt::Debug for EnvStrDebug<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { slice } = self; - f.debug_list() - .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap()))) - .finish() - } -} - -impl Env { - pub fn str_debug(&self) -> impl fmt::Debug + '_ { - let Self { iter } = self; - EnvStrDebug { slice: iter.as_slice() } - } -} - -impl fmt::Debug for Env { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { iter } = self; - f.debug_list().entries(iter.as_slice()).finish() - } -} - -impl !Send for Env {} -impl !Sync for Env {} - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -pub fn env() -> Env { - unsafe { - let _guard = env_read_lock(); - - // Use `__wasilibc_get_environ` instead of `environ` here so that we - // don't require wasi-libc to eagerly initialize the environment - // variables. - let mut environ = libc::__wasilibc_get_environ(); - - let mut result = Vec::new(); - if !environ.is_null() { - while !(*environ).is_null() { - if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) { - result.push(key_value); - } - environ = environ.add(1); - } - } - return Env { iter: result.into_iter() }; - } - - // See src/libstd/sys/pal/unix/os.rs, same as that - fn parse(input: &[u8]) -> Option<(OsString, OsString)> { - if input.is_empty() { - return None; - } - let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1); - pos.map(|p| { - ( - OsStringExt::from_vec(input[..p].to_vec()), - OsStringExt::from_vec(input[p + 1..].to_vec()), - ) - }) - } -} - -pub fn getenv(k: &OsStr) -> Option { - // environment variables with a nul byte can't be set, so their value is - // always None as well - run_with_cstr(k.as_bytes(), &|k| { - let _guard = env_read_lock(); - let v = unsafe { libc::getenv(k.as_ptr()) } as *const libc::c_char; - - if v.is_null() { - Ok(None) - } else { - // SAFETY: `v` cannot be mutated while executing this line since we've a read lock - let bytes = unsafe { CStr::from_ptr(v) }.to_bytes().to_vec(); - - Ok(Some(OsStringExt::from_vec(bytes))) - } - }) - .ok() - .flatten() -} - -pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { - run_with_cstr(k.as_bytes(), &|k| { - run_with_cstr(v.as_bytes(), &|v| unsafe { - let _guard = env_write_lock(); - cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(drop) - }) - }) -} - -pub unsafe fn unsetenv(n: &OsStr) -> io::Result<()> { - run_with_cstr(n.as_bytes(), &|nbuf| unsafe { - let _guard = env_write_lock(); - cvt(libc::unsetenv(nbuf.as_ptr())).map(drop) - }) -} - #[allow(dead_code)] pub fn page_size() -> usize { unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize } @@ -294,6 +152,6 @@ macro_rules! impl_is_minus_one { impl_is_minus_one! { i8 i16 i32 i64 isize } -fn cvt(t: T) -> io::Result { +pub fn cvt(t: T) -> io::Result { if t.is_minus_one() { Err(io::Error::last_os_error()) } else { Ok(t) } } diff --git a/library/std/src/sys/pal/windows/os.rs b/library/std/src/sys/pal/windows/os.rs index 044dc2e8cd8f..f331282d2d72 100644 --- a/library/std/src/sys/pal/windows/os.rs +++ b/library/std/src/sys/pal/windows/os.rs @@ -5,16 +5,16 @@ #[cfg(test)] mod tests; +use super::api; #[cfg(not(target_vendor = "uwp"))] use super::api::WinError; -use super::{api, to_u16s}; use crate::error::Error as StdError; use crate::ffi::{OsStr, OsString}; use crate::os::windows::ffi::EncodeWide; use crate::os::windows::prelude::*; use crate::path::{self, PathBuf}; -use crate::sys::{c, cvt}; -use crate::{fmt, io, ptr, slice}; +use crate::sys::pal::{c, cvt}; +use crate::{fmt, io, ptr}; pub fn errno() -> i32 { api::get_last_error().code as i32 @@ -76,108 +76,6 @@ pub fn error_string(mut errnum: i32) -> String { } } -pub struct Env { - base: *mut c::WCHAR, - iter: EnvIterator, -} - -// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. -pub struct EnvStrDebug<'a> { - iter: &'a EnvIterator, -} - -impl fmt::Debug for EnvStrDebug<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { iter } = self; - let iter: EnvIterator = (*iter).clone(); - let mut list = f.debug_list(); - for (a, b) in iter { - list.entry(&(a.to_str().unwrap(), b.to_str().unwrap())); - } - list.finish() - } -} - -impl Env { - pub fn str_debug(&self) -> impl fmt::Debug + '_ { - let Self { base: _, iter } = self; - EnvStrDebug { iter } - } -} - -impl fmt::Debug for Env { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { base: _, iter } = self; - f.debug_list().entries(iter.clone()).finish() - } -} - -impl Iterator for Env { - type Item = (OsString, OsString); - - fn next(&mut self) -> Option<(OsString, OsString)> { - let Self { base: _, iter } = self; - iter.next() - } -} - -#[derive(Clone)] -struct EnvIterator(*mut c::WCHAR); - -impl Iterator for EnvIterator { - type Item = (OsString, OsString); - - fn next(&mut self) -> Option<(OsString, OsString)> { - let Self(cur) = self; - loop { - unsafe { - if **cur == 0 { - return None; - } - let p = *cur as *const u16; - let mut len = 0; - while *p.add(len) != 0 { - len += 1; - } - let s = slice::from_raw_parts(p, len); - *cur = cur.add(len + 1); - - // Windows allows environment variables to start with an equals - // symbol (in any other position, this is the separator between - // variable name and value). Since`s` has at least length 1 at - // this point (because the empty string terminates the array of - // environment variables), we can safely slice. - let pos = match s[1..].iter().position(|&u| u == b'=' as u16).map(|p| p + 1) { - Some(p) => p, - None => continue, - }; - return Some(( - OsStringExt::from_wide(&s[..pos]), - OsStringExt::from_wide(&s[pos + 1..]), - )); - } - } - } -} - -impl Drop for Env { - fn drop(&mut self) { - unsafe { - c::FreeEnvironmentStringsW(self.base); - } - } -} - -pub fn env() -> Env { - unsafe { - let ch = c::GetEnvironmentStringsW(); - if ch.is_null() { - panic!("failure getting env string from OS: {}", io::Error::last_os_error()); - } - Env { base: ch, iter: EnvIterator(ch) } - } -} - pub struct SplitPaths<'a> { data: EncodeWide<'a>, must_yield: bool, @@ -290,33 +188,6 @@ pub fn chdir(p: &path::Path) -> io::Result<()> { cvt(unsafe { c::SetCurrentDirectoryW(p.as_ptr()) }).map(drop) } -pub fn getenv(k: &OsStr) -> Option { - let k = to_u16s(k).ok()?; - super::fill_utf16_buf( - |buf, sz| unsafe { c::GetEnvironmentVariableW(k.as_ptr(), buf, sz) }, - OsStringExt::from_wide, - ) - .ok() -} - -pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { - // SAFETY: We ensure that k and v are null-terminated wide strings. - unsafe { - let k = to_u16s(k)?; - let v = to_u16s(v)?; - - cvt(c::SetEnvironmentVariableW(k.as_ptr(), v.as_ptr())).map(drop) - } -} - -pub unsafe fn unsetenv(n: &OsStr) -> io::Result<()> { - // SAFETY: We ensure that v is a null-terminated wide strings. - unsafe { - let v = to_u16s(n)?; - cvt(c::SetEnvironmentVariableW(v.as_ptr(), ptr::null())).map(drop) - } -} - pub fn temp_dir() -> PathBuf { super::fill_utf16_buf(|buf, sz| unsafe { c::GetTempPath2W(sz, buf) }, super::os2path).unwrap() } diff --git a/library/std/src/sys/pal/xous/os.rs b/library/std/src/sys/pal/xous/os.rs index 2c87e7d91f27..1b41575358f1 100644 --- a/library/std/src/sys/pal/xous/os.rs +++ b/library/std/src/sys/pal/xous/os.rs @@ -1,13 +1,11 @@ use super::unsupported; -use crate::collections::HashMap; use crate::error::Error as StdError; use crate::ffi::{OsStr, OsString}; use crate::marker::PhantomData; use crate::os::xous::ffi::Error as XousError; use crate::path::{self, PathBuf}; -use crate::sync::atomic::{AtomicPtr, AtomicUsize, Ordering}; -use crate::sync::{Mutex, Once}; -use crate::{fmt, io, vec}; +use crate::sync::atomic::{AtomicPtr, Ordering}; +use crate::{fmt, io}; pub(crate) mod params; @@ -136,100 +134,6 @@ pub(crate) fn get_application_parameters() -> Option>; - -fn get_env_store() -> &'static EnvStore { - ENV_INIT.call_once(|| { - let env_store = EnvStore::default(); - if let Some(params) = get_application_parameters() { - for param in params { - if let Ok(envs) = params::EnvironmentBlock::try_from(¶m) { - let mut env_store = env_store.lock().unwrap(); - for env in envs { - env_store.insert(env.key.into(), env.value.into()); - } - break; - } - } - } - ENV.store(Box::into_raw(Box::new(env_store)) as _, Ordering::Relaxed) - }); - unsafe { &*core::ptr::with_exposed_provenance::(ENV.load(Ordering::Relaxed)) } -} - -pub struct Env { - iter: vec::IntoIter<(OsString, OsString)>, -} - -// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. -pub struct EnvStrDebug<'a> { - slice: &'a [(OsString, OsString)], -} - -impl fmt::Debug for EnvStrDebug<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { slice } = self; - f.debug_list() - .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap()))) - .finish() - } -} - -impl Env { - // FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. - pub fn str_debug(&self) -> impl fmt::Debug + '_ { - let Self { iter } = self; - EnvStrDebug { slice: iter.as_slice() } - } -} - -impl fmt::Debug for Env { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { iter } = self; - f.debug_list().entries(iter.as_slice()).finish() - } -} - -impl !Send for Env {} -impl !Sync for Env {} - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -pub fn env() -> Env { - let clone_to_vec = |map: &HashMap| -> Vec<_> { - map.iter().map(|(k, v)| (k.clone(), v.clone())).collect() - }; - - let iter = clone_to_vec(&*get_env_store().lock().unwrap()).into_iter(); - Env { iter } -} - -pub fn getenv(k: &OsStr) -> Option { - get_env_store().lock().unwrap().get(k).cloned() -} - -pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { - let (k, v) = (k.to_owned(), v.to_owned()); - get_env_store().lock().unwrap().insert(k, v); - Ok(()) -} - -pub unsafe fn unsetenv(k: &OsStr) -> io::Result<()> { - get_env_store().lock().unwrap().remove(k); - Ok(()) -} - pub fn temp_dir() -> PathBuf { panic!("no filesystem on this platform") } diff --git a/library/std/src/sys/pal/zkvm/os.rs b/library/std/src/sys/pal/zkvm/os.rs index 868b19e33b67..a8ef97ecf67a 100644 --- a/library/std/src/sys/pal/zkvm/os.rs +++ b/library/std/src/sys/pal/zkvm/os.rs @@ -1,10 +1,8 @@ -use super::{WORD_SIZE, abi, unsupported}; +use super::unsupported; use crate::error::Error as StdError; use crate::ffi::{OsStr, OsString}; use crate::marker::PhantomData; use crate::path::{self, PathBuf}; -use crate::sys::os_str; -use crate::sys_common::FromInner; use crate::{fmt, io}; pub fn errno() -> i32 { @@ -64,64 +62,6 @@ pub fn current_exe() -> io::Result { unsupported() } -pub struct Env(!); - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - self.0 - } -} - -pub fn env() -> Env { - panic!("not supported on this platform") -} - -impl Env { - pub fn str_debug(&self) -> impl fmt::Debug + '_ { - let Self(inner) = self; - match *inner {} - } -} - -impl fmt::Debug for Env { - fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self(inner) = self; - match *inner {} - } -} - -pub fn getenv(varname: &OsStr) -> Option { - let varname = varname.as_encoded_bytes(); - let nbytes = - unsafe { abi::sys_getenv(crate::ptr::null_mut(), 0, varname.as_ptr(), varname.len()) }; - if nbytes == usize::MAX { - return None; - } - - let nwords = (nbytes + WORD_SIZE - 1) / WORD_SIZE; - let words = unsafe { abi::sys_alloc_words(nwords) }; - - let nbytes2 = unsafe { abi::sys_getenv(words, nwords, varname.as_ptr(), varname.len()) }; - debug_assert_eq!(nbytes, nbytes2); - - // Convert to OsString. - // - // FIXME: We can probably get rid of the extra copy here if we - // reimplement "os_str" instead of just using the generic unix - // "os_str". - let u8s: &[u8] = unsafe { crate::slice::from_raw_parts(words.cast() as *const u8, nbytes) }; - Some(OsString::from_inner(os_str::Buf { inner: u8s.to_vec() })) -} - -pub unsafe fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> { - Err(io::const_error!(io::ErrorKind::Unsupported, "cannot set env vars on this platform")) -} - -pub unsafe fn unsetenv(_: &OsStr) -> io::Result<()> { - Err(io::const_error!(io::ErrorKind::Unsupported, "cannot unset env vars on this platform")) -} - pub fn temp_dir() -> PathBuf { panic!("no filesystem on this platform") } diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs index 3b04ec50db30..f594ba5c200a 100644 --- a/library/std/src/sys/process/unix/unix.rs +++ b/library/std/src/sys/process/unix/unix.rs @@ -88,7 +88,7 @@ impl Command { // in its own process. Thus the parent drops the lock guard immediately. // The child calls `mem::forget` to leak the lock, which is crucial because // releasing a lock is not async-signal-safe. - let env_lock = sys::os::env_read_lock(); + let env_lock = sys::env::env_read_lock(); let pid = unsafe { self.do_fork()? }; if pid == 0 { @@ -237,7 +237,7 @@ impl Command { // Similar to when forking, we want to ensure that access to // the environment is synchronized, so make sure to grab the // environment lock before we try to exec. - let _lock = sys::os::env_read_lock(); + let _lock = sys::env::env_read_lock(); let Err(e) = self.do_exec(theirs, envp.as_ref()); e @@ -386,13 +386,13 @@ impl Command { impl Drop for Reset { fn drop(&mut self) { unsafe { - *sys::os::environ() = self.0; + *sys::env::environ() = self.0; } } } - _reset = Some(Reset(*sys::os::environ())); - *sys::os::environ() = envp.as_ptr(); + _reset = Some(Reset(*sys::env::environ())); + *sys::env::environ() = envp.as_ptr(); } libc::execvp(self.get_program_cstr().as_ptr(), self.get_argv().as_ptr()); @@ -735,8 +735,8 @@ impl Command { cvt_nz(libc::posix_spawnattr_setflags(attrs.0.as_mut_ptr(), flags as _))?; // Make sure we synchronize access to the global `environ` resource - let _env_lock = sys::os::env_read_lock(); - let envp = envp.map(|c| c.as_ptr()).unwrap_or_else(|| *sys::os::environ() as *const _); + let _env_lock = sys::env::env_read_lock(); + let envp = envp.map(|c| c.as_ptr()).unwrap_or_else(|| *sys::env::environ() as *const _); #[cfg(not(target_os = "nto"))] let spawn_fn = libc::posix_spawnp; diff --git a/library/std/src/sys/process/unix/vxworks.rs b/library/std/src/sys/process/unix/vxworks.rs index 5f1727789a1b..b92446f0cf67 100644 --- a/library/std/src/sys/process/unix/vxworks.rs +++ b/library/std/src/sys/process/unix/vxworks.rs @@ -67,7 +67,7 @@ impl Command { let c_envp = envp .as_ref() .map(|c| c.as_ptr()) - .unwrap_or_else(|| *sys::os::environ() as *const _); + .unwrap_or_else(|| *sys::env::environ() as *const _); let stack_size = crate::cmp::max( crate::env::var_os("RUST_MIN_STACK") .and_then(|s| s.to_str().and_then(|s| s.parse().ok())) @@ -76,7 +76,7 @@ impl Command { ); // ensure that access to the environment is synchronized - let _lock = sys::os::env_read_lock(); + let _lock = sys::env::env_read_lock(); let ret = libc::rtpSpawn( self.get_program_cstr().as_ptr(), From 6518bcb96785ad16413d11d571987079b45da90e Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Mon, 21 Apr 2025 21:17:16 -0700 Subject: [PATCH 07/17] Fix `unsafe_op_in_unsafe_fn` for Unix env --- library/std/src/sys/env/mod.rs | 2 +- library/std/src/sys/env/unix.rs | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/library/std/src/sys/env/mod.rs b/library/std/src/sys/env/mod.rs index bfd3e7fe8bed..0ae7ef53addb 100644 --- a/library/std/src/sys/env/mod.rs +++ b/library/std/src/sys/env/mod.rs @@ -1,6 +1,6 @@ //! Platform-dependent environment variables abstraction. -#![deny(unsafe_op_in_unsafe_fn)] +#![forbid(unsafe_op_in_unsafe_fn)] cfg_if::cfg_if! { if #[cfg(target_family = "unix")] { diff --git a/library/std/src/sys/env/unix.rs b/library/std/src/sys/env/unix.rs index 906a9b40112a..73aacfcad3b4 100644 --- a/library/std/src/sys/env/unix.rs +++ b/library/std/src/sys/env/unix.rs @@ -1,5 +1,3 @@ -#![allow(unsafe_op_in_unsafe_fn)] - use core::slice::memchr; use libc::c_char; @@ -81,7 +79,7 @@ impl Iterator for Env { // desirable anyhow? Though it also means that we have to link to Foundation. #[cfg(target_vendor = "apple")] pub unsafe fn environ() -> *mut *const *const c_char { - libc::_NSGetEnviron() as *mut *const *const c_char + unsafe { libc::_NSGetEnviron() as *mut *const *const c_char } } // Use the `environ` static which is part of POSIX. @@ -159,7 +157,7 @@ pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { run_with_cstr(k.as_bytes(), &|k| { run_with_cstr(v.as_bytes(), &|v| { let _guard = ENV_LOCK.write(); - cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(drop) + cvt(unsafe { libc::setenv(k.as_ptr(), v.as_ptr(), 1) }).map(drop) }) }) } @@ -167,6 +165,6 @@ pub unsafe fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { pub unsafe fn unsetenv(n: &OsStr) -> io::Result<()> { run_with_cstr(n.as_bytes(), &|nbuf| { let _guard = ENV_LOCK.write(); - cvt(libc::unsetenv(nbuf.as_ptr())).map(drop) + cvt(unsafe { libc::unsetenv(nbuf.as_ptr()) }).map(drop) }) } From 1b00ebefdfffc88dbcbf6057d156c5e62434ad43 Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Mon, 21 Apr 2025 21:23:32 -0700 Subject: [PATCH 08/17] Update !DynSend and !DynSync platform impls These have grown out of sync with the platforms. --- compiler/rustc_data_structures/src/marker.rs | 22 ++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs index 5f07cfef1335..dfd9bd320761 100644 --- a/compiler/rustc_data_structures/src/marker.rs +++ b/compiler/rustc_data_structures/src/marker.rs @@ -39,8 +39,15 @@ impls_dyn_send_neg!( [std::io::StderrLock<'_>] ); -#[cfg(any(unix, target_os = "hermit", target_os = "wasi", target_os = "solid_asp3"))] -// Consistent with `std`, `os_imp::Env` is `!Sync` in these platforms +#[cfg(any( + unix, + target_os = "hermit", + all(target_vendor = "fortanix", target_env = "sgx"), + target_os = "solid_asp3", + target_os = "wasi", + target_os = "xous" +))] +// Consistent with `std`, `env_imp::Env` is `!Sync` in these platforms impl !DynSend for std::env::VarsOs {} macro_rules! already_send { @@ -106,8 +113,15 @@ impls_dyn_sync_neg!( [std::sync::mpsc::Sender where T] ); -#[cfg(any(unix, target_os = "hermit", target_os = "wasi", target_os = "solid_asp3"))] -// Consistent with `std`, `os_imp::Env` is `!Sync` in these platforms +#[cfg(any( + unix, + target_os = "hermit", + all(target_vendor = "fortanix", target_env = "sgx"), + target_os = "solid_asp3", + target_os = "wasi", + target_os = "xous" +))] +// Consistent with `std`, `env_imp::Env` is `!Sync` in these platforms impl !DynSync for std::env::VarsOs {} macro_rules! already_sync { From 46952125661fa7bb6a016a6be4e03620da16a077 Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Mon, 21 Apr 2025 21:58:58 -0700 Subject: [PATCH 09/17] Deduplicate unsupported env items --- library/std/src/sys/env/unsupported.rs | 9 ++---- library/std/src/sys/env/zkvm.rs | 41 ++++---------------------- 2 files changed, 8 insertions(+), 42 deletions(-) diff --git a/library/std/src/sys/env/unsupported.rs b/library/std/src/sys/env/unsupported.rs index 7ad76d8e31ca..98905e648274 100644 --- a/library/std/src/sys/env/unsupported.rs +++ b/library/std/src/sys/env/unsupported.rs @@ -6,23 +6,20 @@ pub struct Env(!); impl Env { // FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. pub fn str_debug(&self) -> impl fmt::Debug + '_ { - let Self(inner) = self; - match *inner {} + self.0 } } impl fmt::Debug for Env { fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self(inner) = self; - match *inner {} + self.0 } } impl Iterator for Env { type Item = (OsString, OsString); fn next(&mut self) -> Option<(OsString, OsString)> { - let Self(inner) = self; - match *inner {} + self.0 } } diff --git a/library/std/src/sys/env/zkvm.rs b/library/std/src/sys/env/zkvm.rs index 8d0bf7a198ed..2eb7005ba128 100644 --- a/library/std/src/sys/env/zkvm.rs +++ b/library/std/src/sys/env/zkvm.rs @@ -1,35 +1,12 @@ +#[expect(dead_code)] +#[path = "unsupported.rs"] +mod unsupported_env; +pub use unsupported_env::{Env, env, setenv, unsetenv}; + use crate::ffi::{OsStr, OsString}; use crate::sys::os_str; use crate::sys::pal::{WORD_SIZE, abi}; use crate::sys_common::FromInner; -use crate::{fmt, io}; - -pub struct Env(!); - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - self.0 - } -} - -pub fn env() -> Env { - panic!("not supported on this platform") -} - -impl Env { - pub fn str_debug(&self) -> impl fmt::Debug + '_ { - let Self(inner) = self; - match *inner {} - } -} - -impl fmt::Debug for Env { - fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self(inner) = self; - match *inner {} - } -} pub fn getenv(varname: &OsStr) -> Option { let varname = varname.as_encoded_bytes(); @@ -53,11 +30,3 @@ pub fn getenv(varname: &OsStr) -> Option { let u8s: &[u8] = unsafe { crate::slice::from_raw_parts(words.cast() as *const u8, nbytes) }; Some(OsString::from_inner(os_str::Buf { inner: u8s.to_vec() })) } - -pub unsafe fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> { - Err(io::const_error!(io::ErrorKind::Unsupported, "cannot set env vars on this platform")) -} - -pub unsafe fn unsetenv(_: &OsStr) -> io::Result<()> { - Err(io::const_error!(io::ErrorKind::Unsupported, "cannot unset env vars on this platform")) -} From 01485c9fe9a50b48fd4c78e7116dcaa2aeb87a40 Mon Sep 17 00:00:00 2001 From: Thalia Archibald Date: Mon, 21 Apr 2025 22:24:02 -0700 Subject: [PATCH 10/17] Unify owned `Env` types between platforms Also, update the same pattern of reuse in `sys::args` to match. --- library/std/src/sys/args/mod.rs | 10 ++++++ library/std/src/sys/args/uefi.rs | 5 +-- library/std/src/sys/args/unix.rs | 5 +-- library/std/src/sys/args/wasi.rs | 5 +-- library/std/src/sys/args/windows.rs | 5 +-- library/std/src/sys/args/xous.rs | 5 +-- library/std/src/sys/env/common.rs | 48 +++++++++++++++++++++++++ library/std/src/sys/env/hermit.rs | 52 +++------------------------ library/std/src/sys/env/mod.rs | 11 ++++++ library/std/src/sys/env/sgx.rs | 55 +++-------------------------- library/std/src/sys/env/solid.rs | 50 ++------------------------ library/std/src/sys/env/uefi.rs | 42 ++-------------------- library/std/src/sys/env/unix.rs | 50 ++------------------------ library/std/src/sys/env/wasi.rs | 50 ++------------------------ library/std/src/sys/env/xous.rs | 53 +++------------------------ 15 files changed, 98 insertions(+), 348 deletions(-) create mode 100644 library/std/src/sys/env/common.rs diff --git a/library/std/src/sys/args/mod.rs b/library/std/src/sys/args/mod.rs index 6a37b32d2293..0011f55dc14e 100644 --- a/library/std/src/sys/args/mod.rs +++ b/library/std/src/sys/args/mod.rs @@ -2,6 +2,16 @@ #![forbid(unsafe_op_in_unsafe_fn)] +#[cfg(any( + all(target_family = "unix", not(any(target_os = "espidf", target_os = "vita"))), + target_family = "windows", + target_os = "hermit", + target_os = "uefi", + target_os = "wasi", + target_os = "xous", +))] +mod common; + cfg_if::cfg_if! { if #[cfg(any( all(target_family = "unix", not(any(target_os = "espidf", target_os = "vita"))), diff --git a/library/std/src/sys/args/uefi.rs b/library/std/src/sys/args/uefi.rs index 84406c7f69df..02dada382eff 100644 --- a/library/std/src/sys/args/uefi.rs +++ b/library/std/src/sys/args/uefi.rs @@ -1,14 +1,11 @@ use r_efi::protocols::loaded_image; +pub use super::common::Args; use crate::env::current_exe; use crate::ffi::OsString; use crate::iter::Iterator; use crate::sys::pal::helpers; -#[path = "common.rs"] -mod common; -pub use common::Args; - pub fn args() -> Args { let lazy_current_exe = || Vec::from([current_exe().map(Into::into).unwrap_or_default()]); diff --git a/library/std/src/sys/args/unix.rs b/library/std/src/sys/args/unix.rs index c087fd629651..a7b79ad396e7 100644 --- a/library/std/src/sys/args/unix.rs +++ b/library/std/src/sys/args/unix.rs @@ -5,16 +5,13 @@ #![allow(dead_code)] // runtime init functions not used during testing +pub use super::common::Args; use crate::ffi::CStr; #[cfg(target_os = "hermit")] use crate::os::hermit::ffi::OsStringExt; #[cfg(not(target_os = "hermit"))] use crate::os::unix::ffi::OsStringExt; -#[path = "common.rs"] -mod common; -pub use common::Args; - /// One-time global initialization. pub unsafe fn init(argc: isize, argv: *const *const u8) { unsafe { imp::init(argc, argv) } diff --git a/library/std/src/sys/args/wasi.rs b/library/std/src/sys/args/wasi.rs index 4795789e4c71..72063a87dc9f 100644 --- a/library/std/src/sys/args/wasi.rs +++ b/library/std/src/sys/args/wasi.rs @@ -1,12 +1,9 @@ #![forbid(unsafe_op_in_unsafe_fn)] +pub use super::common::Args; use crate::ffi::{CStr, OsStr, OsString}; use crate::os::wasi::ffi::OsStrExt; -#[path = "common.rs"] -mod common; -pub use common::Args; - /// Returns the command line arguments pub fn args() -> Args { Args::new(maybe_args().unwrap_or(Vec::new())) diff --git a/library/std/src/sys/args/windows.rs b/library/std/src/sys/args/windows.rs index 47f0e5f2d05f..81c44fabdcc6 100644 --- a/library/std/src/sys/args/windows.rs +++ b/library/std/src/sys/args/windows.rs @@ -6,6 +6,7 @@ #[cfg(test)] mod tests; +pub use super::common::Args; use crate::ffi::{OsStr, OsString}; use crate::num::NonZero; use crate::os::windows::prelude::*; @@ -18,10 +19,6 @@ use crate::sys_common::AsInner; use crate::sys_common::wstr::WStrUnits; use crate::{io, iter, ptr}; -#[path = "common.rs"] -mod common; -pub use common::Args; - pub fn args() -> Args { // SAFETY: `GetCommandLineW` returns a pointer to a null terminated UTF-16 // string so it's safe for `WStrUnits` to use. diff --git a/library/std/src/sys/args/xous.rs b/library/std/src/sys/args/xous.rs index 09a47283d657..2010bad14d1f 100644 --- a/library/std/src/sys/args/xous.rs +++ b/library/std/src/sys/args/xous.rs @@ -1,10 +1,7 @@ +pub use super::common::Args; use crate::sys::pal::os::get_application_parameters; use crate::sys::pal::os::params::ArgumentList; -#[path = "common.rs"] -mod common; -pub use common::Args; - pub fn args() -> Args { let Some(params) = get_application_parameters() else { return Args::new(vec![]); diff --git a/library/std/src/sys/env/common.rs b/library/std/src/sys/env/common.rs new file mode 100644 index 000000000000..f161ff073f3d --- /dev/null +++ b/library/std/src/sys/env/common.rs @@ -0,0 +1,48 @@ +use crate::ffi::OsString; +use crate::{fmt, vec}; + +pub struct Env { + iter: vec::IntoIter<(OsString, OsString)>, +} + +// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. +pub struct EnvStrDebug<'a> { + slice: &'a [(OsString, OsString)], +} + +impl fmt::Debug for EnvStrDebug<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list() + .entries(self.slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap()))) + .finish() + } +} + +impl Env { + pub(super) fn new(env: Vec<(OsString, OsString)>) -> Self { + Env { iter: env.into_iter() } + } + + pub fn str_debug(&self) -> impl fmt::Debug + '_ { + EnvStrDebug { slice: self.iter.as_slice() } + } +} + +impl fmt::Debug for Env { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter.as_slice()).finish() + } +} + +impl !Send for Env {} +impl !Sync for Env {} + +impl Iterator for Env { + type Item = (OsString, OsString); + fn next(&mut self) -> Option<(OsString, OsString)> { + self.iter.next() + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} diff --git a/library/std/src/sys/env/hermit.rs b/library/std/src/sys/env/hermit.rs index 4c7d7e80a350..445ecdeb6a39 100644 --- a/library/std/src/sys/env/hermit.rs +++ b/library/std/src/sys/env/hermit.rs @@ -1,10 +1,11 @@ use core::slice::memchr; +pub use super::common::Env; use crate::collections::HashMap; use crate::ffi::{CStr, OsStr, OsString, c_char}; +use crate::io; use crate::os::hermit::ffi::OsStringExt; use crate::sync::Mutex; -use crate::{fmt, io, vec}; static ENV: Mutex>> = Mutex::new(None); @@ -44,60 +45,15 @@ pub fn init(env: *const *const c_char) { } } -pub struct Env { - iter: vec::IntoIter<(OsString, OsString)>, -} - -// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. -pub struct EnvStrDebug<'a> { - slice: &'a [(OsString, OsString)], -} - -impl fmt::Debug for EnvStrDebug<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { slice } = self; - f.debug_list() - .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap()))) - .finish() - } -} - -impl Env { - pub fn str_debug(&self) -> impl fmt::Debug + '_ { - let Self { iter } = self; - EnvStrDebug { slice: iter.as_slice() } - } -} - -impl fmt::Debug for Env { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { iter } = self; - f.debug_list().entries(iter.as_slice()).finish() - } -} - -impl !Send for Env {} -impl !Sync for Env {} - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - /// Returns a vector of (variable, value) byte-vector pairs for all the /// environment variables of the current process. pub fn env() -> Env { let guard = ENV.lock().unwrap(); let env = guard.as_ref().unwrap(); - let result = env.iter().map(|(key, value)| (key.clone(), value.clone())).collect::>(); + let result = env.iter().map(|(key, value)| (key.clone(), value.clone())).collect(); - Env { iter: result.into_iter() } + Env::new(result) } pub fn getenv(k: &OsStr) -> Option { diff --git a/library/std/src/sys/env/mod.rs b/library/std/src/sys/env/mod.rs index 0ae7ef53addb..d81ff875c830 100644 --- a/library/std/src/sys/env/mod.rs +++ b/library/std/src/sys/env/mod.rs @@ -2,6 +2,17 @@ #![forbid(unsafe_op_in_unsafe_fn)] +#[cfg(any( + target_family = "unix", + target_os = "hermit", + all(target_vendor = "fortanix", target_env = "sgx"), + target_os = "solid_asp3", + target_os = "uefi", + target_os = "wasi", + target_os = "xous", +))] +mod common; + cfg_if::cfg_if! { if #[cfg(target_family = "unix")] { mod unix; diff --git a/library/std/src/sys/env/sgx.rs b/library/std/src/sys/env/sgx.rs index 7a48fb1872ba..85be9cd6ad41 100644 --- a/library/std/src/sys/env/sgx.rs +++ b/library/std/src/sys/env/sgx.rs @@ -1,10 +1,11 @@ #![allow(fuzzy_provenance_casts)] // FIXME: this module systematically confuses pointers and integers +pub use super::common::Env; use crate::collections::HashMap; use crate::ffi::{OsStr, OsString}; +use crate::io; use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sync::{Mutex, Once}; -use crate::{fmt, io, vec}; // Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests #[cfg_attr(test, linkage = "available_externally")] @@ -27,61 +28,13 @@ fn create_env_store() -> &'static EnvStore { unsafe { &*(ENV.load(Ordering::Relaxed) as *const EnvStore) } } -pub struct Env { - iter: vec::IntoIter<(OsString, OsString)>, -} - -// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. -pub struct EnvStrDebug<'a> { - slice: &'a [(OsString, OsString)], -} - -impl fmt::Debug for EnvStrDebug<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { slice } = self; - f.debug_list() - .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap()))) - .finish() - } -} - -impl Env { - pub fn str_debug(&self) -> impl fmt::Debug + '_ { - let Self { iter } = self; - EnvStrDebug { slice: iter.as_slice() } - } -} - -impl fmt::Debug for Env { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { iter } = self; - f.debug_list().entries(iter.as_slice()).finish() - } -} - -impl !Send for Env {} -impl !Sync for Env {} - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - pub fn env() -> Env { let clone_to_vec = |map: &HashMap| -> Vec<_> { map.iter().map(|(k, v)| (k.clone(), v.clone())).collect() }; - let iter = get_env_store() - .map(|env| clone_to_vec(&env.lock().unwrap())) - .unwrap_or_default() - .into_iter(); - Env { iter } + let env = get_env_store().map(|env| clone_to_vec(&env.lock().unwrap())).unwrap_or_default(); + Env::new(env) } pub fn getenv(k: &OsStr) -> Option { diff --git a/library/std/src/sys/env/solid.rs b/library/std/src/sys/env/solid.rs index 0eb801c996ad..ea77fc3c1193 100644 --- a/library/std/src/sys/env/solid.rs +++ b/library/std/src/sys/env/solid.rs @@ -1,11 +1,12 @@ use core::slice::memchr; +pub use super::common::Env; use crate::ffi::{CStr, OsStr, OsString}; +use crate::io; use crate::os::raw::{c_char, c_int}; use crate::os::solid::ffi::{OsStrExt, OsStringExt}; use crate::sync::{PoisonError, RwLock}; use crate::sys::common::small_c_string::run_with_cstr; -use crate::{fmt, io, vec}; static ENV_LOCK: RwLock<()> = RwLock::new(()); @@ -13,51 +14,6 @@ pub fn env_read_lock() -> impl Drop { ENV_LOCK.read().unwrap_or_else(PoisonError::into_inner) } -pub struct Env { - iter: vec::IntoIter<(OsString, OsString)>, -} - -// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. -pub struct EnvStrDebug<'a> { - slice: &'a [(OsString, OsString)], -} - -impl fmt::Debug for EnvStrDebug<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { slice } = self; - f.debug_list() - .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap()))) - .finish() - } -} - -impl Env { - pub fn str_debug(&self) -> impl fmt::Debug + '_ { - let Self { iter } = self; - EnvStrDebug { slice: iter.as_slice() } - } -} - -impl fmt::Debug for Env { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { iter } = self; - f.debug_list().entries(iter.as_slice()).finish() - } -} - -impl !Send for Env {} -impl !Sync for Env {} - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - /// Returns a vector of (variable, value) byte-vector pairs for all the /// environment variables of the current process. pub fn env() -> Env { @@ -76,7 +32,7 @@ pub fn env() -> Env { environ = environ.add(1); } } - return Env { iter: result.into_iter() }; + return Env::new(result); } fn parse(input: &[u8]) -> Option<(OsString, OsString)> { diff --git a/library/std/src/sys/env/uefi.rs b/library/std/src/sys/env/uefi.rs index a26305acf8e0..1561df41cac3 100644 --- a/library/std/src/sys/env/uefi.rs +++ b/library/std/src/sys/env/uefi.rs @@ -1,46 +1,10 @@ +pub use super::common::Env; use crate::ffi::{OsStr, OsString}; -use crate::{fmt, io}; - -pub struct EnvStrDebug<'a> { - iter: &'a [(OsString, OsString)], -} - -impl fmt::Debug for EnvStrDebug<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut list = f.debug_list(); - for (a, b) in self.iter { - list.entry(&(a.to_str().unwrap(), b.to_str().unwrap())); - } - list.finish() - } -} - -pub struct Env(crate::vec::IntoIter<(OsString, OsString)>); - -impl Env { - // FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. - pub fn str_debug(&self) -> impl fmt::Debug + '_ { - EnvStrDebug { iter: self.0.as_slice() } - } -} - -impl Iterator for Env { - type Item = (OsString, OsString); - - fn next(&mut self) -> Option<(OsString, OsString)> { - self.0.next() - } -} - -impl fmt::Debug for Env { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} +use crate::io; pub fn env() -> Env { let env = uefi_env::get_all().expect("not supported on this platform"); - Env(env.into_iter()) + Env::new(env) } pub fn getenv(key: &OsStr) -> Option { diff --git a/library/std/src/sys/env/unix.rs b/library/std/src/sys/env/unix.rs index 73aacfcad3b4..78c7af65f9e3 100644 --- a/library/std/src/sys/env/unix.rs +++ b/library/std/src/sys/env/unix.rs @@ -2,57 +2,13 @@ use core::slice::memchr; use libc::c_char; +pub use super::common::Env; use crate::ffi::{CStr, OsStr, OsString}; +use crate::io; use crate::os::unix::prelude::*; use crate::sync::{PoisonError, RwLock}; use crate::sys::common::small_c_string::run_with_cstr; use crate::sys::cvt; -use crate::{fmt, io, vec}; - -pub struct Env { - iter: vec::IntoIter<(OsString, OsString)>, -} - -// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. -pub struct EnvStrDebug<'a> { - slice: &'a [(OsString, OsString)], -} - -impl fmt::Debug for EnvStrDebug<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { slice } = self; - f.debug_list() - .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap()))) - .finish() - } -} - -impl Env { - pub fn str_debug(&self) -> impl fmt::Debug + '_ { - let Self { iter } = self; - EnvStrDebug { slice: iter.as_slice() } - } -} - -impl fmt::Debug for Env { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { iter } = self; - f.debug_list().entries(iter.as_slice()).finish() - } -} - -impl !Send for Env {} -impl !Sync for Env {} - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} // Use `_NSGetEnviron` on Apple platforms. // @@ -112,7 +68,7 @@ pub fn env() -> Env { environ = environ.add(1); } } - return Env { iter: result.into_iter() }; + return Env::new(result); } fn parse(input: &[u8]) -> Option<(OsString, OsString)> { diff --git a/library/std/src/sys/env/wasi.rs b/library/std/src/sys/env/wasi.rs index 6bdb2d5a547a..3719f9db51eb 100644 --- a/library/std/src/sys/env/wasi.rs +++ b/library/std/src/sys/env/wasi.rs @@ -1,55 +1,11 @@ use core::slice::memchr; +pub use super::common::Env; use crate::ffi::{CStr, OsStr, OsString}; +use crate::io; use crate::os::wasi::prelude::*; use crate::sys::common::small_c_string::run_with_cstr; use crate::sys::pal::os::{cvt, libc}; -use crate::{fmt, io, vec}; - -pub struct Env { - iter: vec::IntoIter<(OsString, OsString)>, -} - -// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. -pub struct EnvStrDebug<'a> { - slice: &'a [(OsString, OsString)], -} - -impl fmt::Debug for EnvStrDebug<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { slice } = self; - f.debug_list() - .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap()))) - .finish() - } -} - -impl Env { - pub fn str_debug(&self) -> impl fmt::Debug + '_ { - let Self { iter } = self; - EnvStrDebug { slice: iter.as_slice() } - } -} - -impl fmt::Debug for Env { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { iter } = self; - f.debug_list().entries(iter.as_slice()).finish() - } -} - -impl !Send for Env {} -impl !Sync for Env {} - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} cfg_if::cfg_if! { if #[cfg(target_feature = "atomics")] { @@ -91,7 +47,7 @@ pub fn env() -> Env { environ = environ.add(1); } } - return Env { iter: result.into_iter() }; + return Env::new(result); } // See src/libstd/sys/pal/unix/os.rs, same as that diff --git a/library/std/src/sys/env/xous.rs b/library/std/src/sys/env/xous.rs index d5b8a1c7fb45..232a3dafb0be 100644 --- a/library/std/src/sys/env/xous.rs +++ b/library/std/src/sys/env/xous.rs @@ -1,9 +1,10 @@ +pub use super::common::Env; use crate::collections::HashMap; use crate::ffi::{OsStr, OsString}; +use crate::io; use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sync::{Mutex, Once}; use crate::sys::pal::os::{get_application_parameters, params}; -use crate::{fmt, io, vec}; static ENV: AtomicUsize = AtomicUsize::new(0); static ENV_INIT: Once = Once::new(); @@ -28,59 +29,13 @@ fn get_env_store() -> &'static EnvStore { unsafe { &*core::ptr::with_exposed_provenance::(ENV.load(Ordering::Relaxed)) } } -pub struct Env { - iter: vec::IntoIter<(OsString, OsString)>, -} - -// FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. -pub struct EnvStrDebug<'a> { - slice: &'a [(OsString, OsString)], -} - -impl fmt::Debug for EnvStrDebug<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { slice } = self; - f.debug_list() - .entries(slice.iter().map(|(a, b)| (a.to_str().unwrap(), b.to_str().unwrap()))) - .finish() - } -} - -impl Env { - // FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when ::fmt matches ::fmt. - pub fn str_debug(&self) -> impl fmt::Debug + '_ { - let Self { iter } = self; - EnvStrDebug { slice: iter.as_slice() } - } -} - -impl fmt::Debug for Env { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Self { iter } = self; - f.debug_list().entries(iter.as_slice()).finish() - } -} - -impl !Send for Env {} -impl !Sync for Env {} - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - pub fn env() -> Env { let clone_to_vec = |map: &HashMap| -> Vec<_> { map.iter().map(|(k, v)| (k.clone(), v.clone())).collect() }; - let iter = clone_to_vec(&*get_env_store().lock().unwrap()).into_iter(); - Env { iter } + let env = clone_to_vec(&*get_env_store().lock().unwrap()); + Env::new(env) } pub fn getenv(k: &OsStr) -> Option { From 7493e1cdf64b381f7eb910da982fcbbad7d64769 Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 23 Apr 2025 15:51:57 +0200 Subject: [PATCH 11/17] Make #![feature(let_chains)] bootstrap conditional in compiler/ --- compiler/rustc_ast/src/lib.rs | 2 +- compiler/rustc_ast_lowering/src/lib.rs | 2 +- compiler/rustc_ast_passes/src/lib.rs | 2 +- compiler/rustc_attr_data_structures/src/lib.rs | 2 +- compiler/rustc_attr_parsing/src/lib.rs | 2 +- compiler/rustc_borrowck/src/lib.rs | 2 +- compiler/rustc_builtin_macros/src/lib.rs | 2 +- compiler/rustc_codegen_llvm/src/lib.rs | 2 +- compiler/rustc_codegen_ssa/src/lib.rs | 2 +- compiler/rustc_const_eval/src/lib.rs | 2 +- compiler/rustc_driver_impl/src/lib.rs | 2 +- compiler/rustc_errors/src/lib.rs | 2 +- compiler/rustc_expand/src/lib.rs | 2 +- compiler/rustc_hir/src/lib.rs | 2 +- compiler/rustc_hir_analysis/src/lib.rs | 2 +- compiler/rustc_hir_pretty/src/lib.rs | 2 +- compiler/rustc_hir_typeck/src/lib.rs | 2 +- compiler/rustc_infer/src/lib.rs | 2 +- compiler/rustc_interface/src/lib.rs | 2 +- compiler/rustc_lint/src/lib.rs | 2 +- compiler/rustc_macros/src/lib.rs | 2 +- compiler/rustc_metadata/src/lib.rs | 2 +- compiler/rustc_middle/src/lib.rs | 2 +- compiler/rustc_mir_build/src/lib.rs | 2 +- compiler/rustc_mir_dataflow/src/lib.rs | 2 +- compiler/rustc_mir_transform/src/lib.rs | 2 +- compiler/rustc_monomorphize/src/lib.rs | 2 +- compiler/rustc_parse/src/lib.rs | 2 +- compiler/rustc_passes/src/lib.rs | 2 +- compiler/rustc_pattern_analysis/src/lib.rs | 2 +- compiler/rustc_privacy/src/lib.rs | 2 +- compiler/rustc_query_system/src/lib.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 2 +- compiler/rustc_sanitizers/src/lib.rs | 2 +- compiler/rustc_session/src/lib.rs | 2 +- compiler/rustc_span/src/lib.rs | 2 +- compiler/rustc_symbol_mangling/src/lib.rs | 2 +- compiler/rustc_target/src/lib.rs | 2 +- compiler/rustc_trait_selection/src/lib.rs | 2 +- compiler/rustc_ty_utils/src/lib.rs | 2 +- 40 files changed, 40 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 294c6c9ba7a5..1471262d2d67 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -6,6 +6,7 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc( html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", test(attr(deny(warnings))) @@ -14,7 +15,6 @@ #![feature(associated_type_defaults)] #![feature(box_patterns)] #![feature(if_let_guard)] -#![feature(let_chains)] #![feature(negative_impls)] #![feature(never_type)] #![feature(rustdoc_internals)] diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index c40987541f4a..3ec00bfce73f 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -32,12 +32,12 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(rust_logo)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(exact_size_is_empty)] #![feature(if_let_guard)] -#![feature(let_chains)] #![feature(rustdoc_internals)] // tidy-alphabetical-end diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs index 093199cf3421..7956057f88ee 100644 --- a/compiler/rustc_ast_passes/src/lib.rs +++ b/compiler/rustc_ast_passes/src/lib.rs @@ -4,11 +4,11 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(rust_logo)] #![feature(box_patterns)] #![feature(if_let_guard)] #![feature(iter_is_partitioned)] -#![feature(let_chains)] #![feature(rustdoc_internals)] // tidy-alphabetical-end diff --git a/compiler/rustc_attr_data_structures/src/lib.rs b/compiler/rustc_attr_data_structures/src/lib.rs index c61b44b273de..679fe935484e 100644 --- a/compiler/rustc_attr_data_structures/src/lib.rs +++ b/compiler/rustc_attr_data_structures/src/lib.rs @@ -1,7 +1,7 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(rust_logo)] -#![feature(let_chains)] #![feature(rustdoc_internals)] // tidy-alphabetical-end diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 249e71ef70dc..b9692c01e2c4 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -77,8 +77,8 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(rust_logo)] -#![feature(let_chains)] #![feature(rustdoc_internals)] // tidy-alphabetical-end diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 3b66142eb2ce..dbf943ffdb62 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2,12 +2,12 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(rust_logo)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(file_buffered)] #![feature(if_let_guard)] -#![feature(let_chains)] #![feature(negative_impls)] #![feature(never_type)] #![feature(rustc_attrs)] diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index bcd40f980e64..70e817db2a63 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -5,6 +5,7 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] @@ -12,7 +13,6 @@ #![feature(box_patterns)] #![feature(decl_macro)] #![feature(if_let_guard)] -#![feature(let_chains)] #![feature(proc_macro_internals)] #![feature(proc_macro_quote)] #![feature(rustdoc_internals)] diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 425381b0ffab..b2feeacdb466 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -6,6 +6,7 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] @@ -15,7 +16,6 @@ #![feature(if_let_guard)] #![feature(impl_trait_in_assoc_type)] #![feature(iter_intersperse)] -#![feature(let_chains)] #![feature(rustdoc_internals)] #![feature(slice_as_array)] #![feature(try_blocks)] diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 5b2ed69535b9..c927aae2c4c2 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -2,13 +2,13 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(file_buffered)] #![feature(if_let_guard)] -#![feature(let_chains)] #![feature(negative_impls)] #![feature(rustdoc_internals)] #![feature(string_from_utf8_lossy_owned)] diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index da52d60ae59f..7a0c2543c300 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -1,12 +1,12 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(rust_logo)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(decl_macro)] #![feature(if_let_guard)] -#![feature(let_chains)] #![feature(never_type)] #![feature(rustdoc_internals)] #![feature(slice_ptr_get)] diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 40cc82727a55..d18fa8928140 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -7,10 +7,10 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(decl_macro)] -#![feature(let_chains)] #![feature(panic_backtrace_config)] #![feature(panic_update_hook)] #![feature(result_flattening)] diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index c0c5dba46772..6f37bad9bb46 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -7,6 +7,7 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(array_windows)] @@ -17,7 +18,6 @@ #![feature(default_field_values)] #![feature(error_reporter)] #![feature(if_let_guard)] -#![feature(let_chains)] #![feature(negative_impls)] #![feature(never_type)] #![feature(rustc_attrs)] diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index 4222c9fe9061..79f838e2e33f 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -1,11 +1,11 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(rust_logo)] #![feature(array_windows)] #![feature(associated_type_defaults)] #![feature(if_let_guard)] -#![feature(let_chains)] #![feature(macro_metavar_expr)] #![feature(map_try_insert)] #![feature(proc_macro_diagnostic)] diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index a84857e3597b..32064f96dd6c 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -4,12 +4,12 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(associated_type_defaults)] #![feature(box_patterns)] #![feature(closure_track_caller)] #![feature(debug_closure_helpers)] #![feature(exhaustive_patterns)] -#![feature(let_chains)] #![feature(negative_impls)] #![feature(never_type)] #![feature(rustc_attrs)] diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index e1ad8124aea7..309b8f2c7613 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -59,6 +59,7 @@ This API is completely unstable and subject to change. #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] @@ -67,7 +68,6 @@ This API is completely unstable and subject to change. #![feature(if_let_guard)] #![feature(iter_from_coroutine)] #![feature(iter_intersperse)] -#![feature(let_chains)] #![feature(never_type)] #![feature(rustdoc_internals)] #![feature(slice_partition_dedup)] diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index ff4385c3bcce..779fae80f19c 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -2,7 +2,7 @@ //! the definitions in this file have equivalents in `rustc_ast_pretty`. // tidy-alphabetical-start -#![feature(let_chains)] +#![cfg_attr(bootstrap, feature(let_chains))] #![recursion_limit = "256"] // tidy-alphabetical-end diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index af8ec3739347..c3717b4efa47 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -1,11 +1,11 @@ // tidy-alphabetical-start #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(array_windows)] #![feature(box_patterns)] #![feature(if_let_guard)] #![feature(iter_intersperse)] -#![feature(let_chains)] #![feature(never_type)] #![feature(try_blocks)] // tidy-alphabetical-end diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index ece18f4ea64e..8b2aab420422 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -16,12 +16,12 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] #![feature(extend_one)] #![feature(iterator_try_collect)] -#![feature(let_chains)] #![feature(rustdoc_internals)] #![recursion_limit = "512"] // For rustdoc // tidy-alphabetical-end diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index 67e0be93523d..412807071830 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -1,8 +1,8 @@ // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(decl_macro)] #![feature(file_buffered)] #![feature(iter_intersperse)] -#![feature(let_chains)] #![feature(try_blocks)] // tidy-alphabetical-end diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 212368bea826..b4bc648c9d81 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -21,6 +21,7 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(array_windows)] @@ -28,7 +29,6 @@ #![feature(box_patterns)] #![feature(if_let_guard)] #![feature(iter_order_by)] -#![feature(let_chains)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] #![feature(try_blocks)] diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index edb25e799045..62ca7ce3ca99 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -1,7 +1,7 @@ // tidy-alphabetical-start #![allow(rustc::default_hash_types)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(if_let_guard)] -#![feature(let_chains)] #![feature(never_type)] #![feature(proc_macro_diagnostic)] #![feature(proc_macro_span)] diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 3b44c44fcb94..3931be1654a3 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -1,5 +1,6 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(coroutines)] @@ -8,7 +9,6 @@ #![feature(file_buffered)] #![feature(if_let_guard)] #![feature(iter_from_coroutine)] -#![feature(let_chains)] #![feature(macro_metavar_expr)] #![feature(min_specialization)] #![feature(never_type)] diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 8fe2cc7101ba..df025aeebf04 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -29,6 +29,7 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::potential_query_instability)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(allocator_api)] @@ -48,7 +49,6 @@ #![feature(if_let_guard)] #![feature(intra_doc_pointers)] #![feature(iter_from_coroutine)] -#![feature(let_chains)] #![feature(min_specialization)] #![feature(negative_impls)] #![feature(never_type)] diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index 8e96d46dac27..a051cf570b7d 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -3,10 +3,10 @@ // tidy-alphabetical-start #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(if_let_guard)] -#![feature(let_chains)] #![feature(try_blocks)] // tidy-alphabetical-end diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index a0efc623b8e7..38f82b127465 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -1,10 +1,10 @@ // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(assert_matches)] #![feature(associated_type_defaults)] #![feature(box_patterns)] #![feature(exact_size_is_empty)] #![feature(file_buffered)] -#![feature(let_chains)] #![feature(never_type)] #![feature(try_blocks)] // tidy-alphabetical-end diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 4d74ecddfb05..a0e2619d0973 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -1,4 +1,5 @@ // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(array_windows)] #![feature(assert_matches)] #![feature(box_patterns)] @@ -7,7 +8,6 @@ #![feature(file_buffered)] #![feature(if_let_guard)] #![feature(impl_trait_in_assoc_type)] -#![feature(let_chains)] #![feature(map_try_insert)] #![feature(never_type)] #![feature(try_blocks)] diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index 8f6914f3d724..8469e0f17a69 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -1,9 +1,9 @@ // tidy-alphabetical-start +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(array_windows)] #![feature(file_buffered)] #![feature(if_let_guard)] #![feature(impl_trait_in_assoc_type)] -#![feature(let_chains)] // tidy-alphabetical-end use rustc_hir::lang_items::LangItem; diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 2edc8c83017d..14a12a831894 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -4,13 +4,13 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(array_windows)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(debug_closure_helpers)] #![feature(if_let_guard)] #![feature(iter_intersperse)] -#![feature(let_chains)] #![feature(string_from_utf8_lossy_owned)] // tidy-alphabetical-end diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 93ff0f66d695..c7bb00df796a 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -6,9 +6,9 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] -#![feature(let_chains)] #![feature(map_try_insert)] #![feature(rustdoc_internals)] #![feature(try_blocks)] diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs index 176dcbf6da42..f63d8b2d79f6 100644 --- a/compiler/rustc_pattern_analysis/src/lib.rs +++ b/compiler/rustc_pattern_analysis/src/lib.rs @@ -6,7 +6,7 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] #![allow(unused_crate_dependencies)] -#![cfg_attr(feature = "rustc", feature(let_chains))] +#![cfg_attr(all(feature = "rustc", bootstrap), feature(let_chains))] // tidy-alphabetical-end pub mod constructor; diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index c7bab828659a..0bde289c85fc 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1,9 +1,9 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(associated_type_defaults)] -#![feature(let_chains)] #![feature(rustdoc_internals)] #![feature(try_blocks)] // tidy-alphabetical-end diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index 2aedd365adc8..b159b876c7e6 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -1,9 +1,9 @@ // tidy-alphabetical-start #![allow(rustc::potential_query_instability, internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(assert_matches)] #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] -#![feature(let_chains)] #![feature(min_specialization)] // tidy-alphabetical-end diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index b121755acd9c..4a252a7b5281 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -10,13 +10,13 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(if_let_guard)] #![feature(iter_intersperse)] -#![feature(let_chains)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] // tidy-alphabetical-end diff --git a/compiler/rustc_sanitizers/src/lib.rs b/compiler/rustc_sanitizers/src/lib.rs index e4792563e71e..729c921450ea 100644 --- a/compiler/rustc_sanitizers/src/lib.rs +++ b/compiler/rustc_sanitizers/src/lib.rs @@ -4,7 +4,7 @@ //! compiler. // tidy-alphabetical-start -#![feature(let_chains)] +#![cfg_attr(bootstrap, feature(let_chains))] // tidy-alphabetical-end pub mod cfi; diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index 0e19b982a133..ec8e9898dc71 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -1,8 +1,8 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![feature(default_field_values)] #![feature(iter_intersperse)] -#![feature(let_chains)] #![feature(rustc_attrs)] // To generate CodegenOptionsTargetModifiers and UnstableOptionsTargetModifiers enums // with macro_rules, it is necessary to use recursive mechanic ("Incremental TT Munchers"). diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index f788fd48037a..fccdaed21a20 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -17,6 +17,7 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(array_windows)] @@ -24,7 +25,6 @@ #![feature(core_io_borrowed_buf)] #![feature(hash_set_entry)] #![feature(if_let_guard)] -#![feature(let_chains)] #![feature(map_try_insert)] #![feature(negative_impls)] #![feature(read_buf)] diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index cc33974cc627..ca8918e06aaf 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -89,9 +89,9 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] -#![feature(let_chains)] #![feature(rustdoc_internals)] // tidy-alphabetical-end diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index df99280f5712..922c18448d51 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -9,12 +9,12 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] #![feature(debug_closure_helpers)] #![feature(iter_intersperse)] -#![feature(let_chains)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] // tidy-alphabetical-end diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index 93c118053045..7613a0cef52a 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -14,6 +14,7 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] @@ -23,7 +24,6 @@ #![feature(if_let_guard)] #![feature(iter_intersperse)] #![feature(iterator_try_reduce)] -#![feature(let_chains)] #![feature(never_type)] #![feature(rustdoc_internals)] #![feature(try_blocks)] diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 35cc6f398565..99252c28b400 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -6,6 +6,7 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] @@ -13,7 +14,6 @@ #![feature(box_patterns)] #![feature(if_let_guard)] #![feature(iterator_try_collect)] -#![feature(let_chains)] #![feature(never_type)] #![feature(rustdoc_internals)] // tidy-alphabetical-end From c0446d3cbb4849dfe1e6824eb20f9fa0426e2d4b Mon Sep 17 00:00:00 2001 From: Hegui Dai Date: Thu, 24 Apr 2025 10:12:14 +0800 Subject: [PATCH 12/17] keep the original text for is_some and is_none --- library/core/src/option.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 9789912719b1..c0005cdee086 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -159,8 +159,8 @@ //! //! ## Querying the variant //! -//! The [`is_some`] and [`is_none`] methods borrow of the [`Option`] -//! and return [`true`] if the [`Option`] is [`Some`] or [`None`], respectively. +//! The [`is_some`] and [`is_none`] methods return [`true`] if the [`Option`] +//! is [`Some`] or [`None`], respectively. //! //! The [`is_some_and`] and [`is_none_or`] methods apply the provided function //! to the contents of the [`Option`] to produce a boolean value. From d0ac97d64910de81cab785055428865f300a86cb Mon Sep 17 00:00:00 2001 From: Hegui Dai Date: Thu, 24 Apr 2025 10:22:49 +0800 Subject: [PATCH 13/17] add examples using .as_ref() for is_some_and and is_none_or --- library/core/src/option.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/library/core/src/option.rs b/library/core/src/option.rs index c0005cdee086..aed5a043c11a 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -638,6 +638,10 @@ impl Option { /// /// let x: Option = None; /// assert_eq!(x.is_some_and(|x| x > 1), false); + /// + /// let x: Option = Some("ownership".to_string()); + /// assert_eq!(x.as_ref().is_some_and(|x| x.len() > 1), true); + /// println!("still alive {:?}", x); /// ``` #[must_use] #[inline] @@ -682,6 +686,10 @@ impl Option { /// /// let x: Option = None; /// assert_eq!(x.is_none_or(|x| x > 1), true); + /// + /// let x: Option = Some("ownership".to_string()); + /// assert_eq!(x.as_ref().is_none_or(|x| x.len() > 1), true); + /// println!("still alive {:?}", x); /// ``` #[must_use] #[inline] From d8528c6a310d3ac64f64a8f5af60ad5e2ad4b081 Mon Sep 17 00:00:00 2001 From: Amanda Stjerna Date: Thu, 24 Apr 2025 17:24:31 +0200 Subject: [PATCH 14/17] Some drive-by housecleaning in `rustc_borrowck` This commit picks up a few odd ends discovered during the work on #130227. It adds some documentation and renames a few methods with too generic names to describe what they actually do. It also adds some debug output that was helpful during bug hunting. --- .../src/diagnostics/bound_region_errors.rs | 39 ++++++++---------- .../src/diagnostics/region_errors.rs | 2 +- .../rustc_borrowck/src/region_infer/mod.rs | 41 +++++++++---------- .../rustc_borrowck/src/region_infer/values.rs | 2 +- 4 files changed, 39 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index aa968a1e40f3..7c9e916fa9ad 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -49,7 +49,7 @@ impl<'tcx> UniverseInfo<'tcx> { UniverseInfo::RelateTys { expected, found } } - pub(crate) fn report_error( + pub(crate) fn report_erroneous_element( &self, mbcx: &mut MirBorrowckCtxt<'_, '_, 'tcx>, placeholder: ty::PlaceholderRegion, @@ -68,7 +68,7 @@ impl<'tcx> UniverseInfo<'tcx> { mbcx.buffer_error(err); } UniverseInfo::TypeOp(ref type_op_info) => { - type_op_info.report_error(mbcx, placeholder, error_element, cause); + type_op_info.report_erroneous_element(mbcx, placeholder, error_element, cause); } UniverseInfo::Other => { // FIXME: This error message isn't great, but it doesn't show @@ -145,8 +145,11 @@ pub(crate) trait TypeOpInfo<'tcx> { error_region: Option>, ) -> Option>; + /// Constraints require that `error_element` appear in the + /// values of `placeholder`, but this cannot be proven to + /// hold. Report an error. #[instrument(level = "debug", skip(self, mbcx))] - fn report_error( + fn report_erroneous_element( &self, mbcx: &mut MirBorrowckCtxt<'_, '_, 'tcx>, placeholder: ty::PlaceholderRegion, @@ -190,12 +193,7 @@ pub(crate) trait TypeOpInfo<'tcx> { let nice_error = self.nice_error(mbcx, cause, placeholder_region, error_region); debug!(?nice_error); - - if let Some(nice_error) = nice_error { - mbcx.buffer_error(nice_error); - } else { - mbcx.buffer_error(self.fallback_error(tcx, span)); - } + mbcx.buffer_error(nice_error.unwrap_or_else(|| self.fallback_error(tcx, span))); } } @@ -450,7 +448,8 @@ fn try_extract_error_from_region_constraints<'a, 'tcx>( ty::ReVar(vid) => universe_of_region(vid), _ => ty::UniverseIndex::ROOT, }; - let matches = + // Are the two regions the same? + let regions_the_same = |a_region: Region<'tcx>, b_region: Region<'tcx>| match (a_region.kind(), b_region.kind()) { (RePlaceholder(a_p), RePlaceholder(b_p)) => a_p.bound == b_p.bound, _ => a_region == b_region, @@ -459,7 +458,7 @@ fn try_extract_error_from_region_constraints<'a, 'tcx>( |constraint: &Constraint<'tcx>, cause: &SubregionOrigin<'tcx>, exact| match *constraint { Constraint::RegSubReg(sub, sup) if ((exact && sup == placeholder_region) - || (!exact && matches(sup, placeholder_region))) + || (!exact && regions_the_same(sup, placeholder_region))) && sup != sub => { Some((sub, cause.clone())) @@ -468,23 +467,21 @@ fn try_extract_error_from_region_constraints<'a, 'tcx>( if (exact && sup == placeholder_region && !universe_of_region(vid).can_name(placeholder_universe)) - || (!exact && matches(sup, placeholder_region)) => + || (!exact && regions_the_same(sup, placeholder_region)) => { Some((ty::Region::new_var(infcx.tcx, vid), cause.clone())) } _ => None, }; - let mut info = region_constraints - .constraints - .iter() - .find_map(|(constraint, cause)| check(constraint, cause, true)); - if info.is_none() { - info = region_constraints + + let mut find_culprit = |exact_match: bool| { + region_constraints .constraints .iter() - .find_map(|(constraint, cause)| check(constraint, cause, false)); - } - let (sub_region, cause) = info?; + .find_map(|(constraint, cause)| check(constraint, cause, exact_match)) + }; + + let (sub_region, cause) = find_culprit(true).or_else(|| find_culprit(false))?; debug!(?sub_region, "cause = {:#?}", cause); let error = match (error_region, *sub_region) { diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 6b11f1a3681f..b2056ccc8c60 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -404,7 +404,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let universe = placeholder.universe; let universe_info = self.regioncx.universe_info(universe); - universe_info.report_error(self, placeholder, error_element, cause); + universe_info.report_erroneous_element(self, placeholder, error_element, cause); } RegionErrorKind::RegionError { fr_origin, longer_fr, shorter_fr, is_reported } => { diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index a80d74d9e370..eebce11da58f 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -1623,30 +1623,23 @@ impl<'tcx> RegionInferenceContext<'tcx> { let longer_fr_scc = self.constraint_sccs.scc(longer_fr); debug!("check_bound_universal_region: longer_fr_scc={:?}", longer_fr_scc,); - for error_element in self.scc_values.elements_contained_in(longer_fr_scc) { - match error_element { - RegionElement::Location(_) | RegionElement::RootUniversalRegion(_) => {} - // If we have some bound universal region `'a`, then the only - // elements it can contain is itself -- we don't know anything - // else about it! - RegionElement::PlaceholderRegion(placeholder1) => { - if placeholder == placeholder1 { - continue; - } - } - } - + // If we have some bound universal region `'a`, then the only + // elements it can contain is itself -- we don't know anything + // else about it! + if let Some(error_element) = self + .scc_values + .elements_contained_in(longer_fr_scc) + .find(|e| *e != RegionElement::PlaceholderRegion(placeholder)) + { + // Stop after the first error, it gets too noisy otherwise, and does not provide more information. errors_buffer.push(RegionErrorKind::BoundUniversalRegionError { longer_fr, error_element, placeholder, }); - - // Stop after the first error, it gets too noisy otherwise, and does not provide more - // information. - break; + } else { + debug!("check_bound_universal_region: all bounds satisfied"); } - debug!("check_bound_universal_region: all bounds satisfied"); } #[instrument(level = "debug", skip(self, infcx, errors_buffer))] @@ -2066,7 +2059,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { constraint.category }; - match category { + let interest = match category { // Returns usually provide a type to blame and have specially written diagnostics, // so prioritize them. ConstraintCategory::Return(_) => 0, @@ -2118,9 +2111,13 @@ impl<'tcx> RegionInferenceContext<'tcx> { // specific, and are not used for relations that would make sense to blame. ConstraintCategory::BoringNoLocation => 6, // Do not blame internal constraints. - ConstraintCategory::Internal => 7, - ConstraintCategory::IllegalUniverse => 8, - } + ConstraintCategory::IllegalUniverse => 7, + ConstraintCategory::Internal => 8, + }; + + debug!("constraint {constraint:?} category: {category:?}, interest: {interest:?}"); + + interest }; let best_choice = if blame_source { diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index d9ac5b5cb132..f1427218cdb0 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -21,7 +21,7 @@ rustc_index::newtype_index! { /// An individual element in a region value -- the value of a /// particular region variable consists of a set of these elements. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub(crate) enum RegionElement { /// A point in the control-flow graph. Location(Location), From e5e3a95c1e411a76a45283ca6c42671024227301 Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 24 Apr 2025 02:32:52 +0000 Subject: [PATCH 15/17] norm nested aliases before evaluating the parent goal --- Cargo.lock | 1 - compiler/rustc_middle/src/ty/predicate.rs | 8 +- compiler/rustc_next_trait_solver/Cargo.toml | 2 - .../src/solve/alias_relate.rs | 11 +- .../src/solve/eval_ctxt/canonical.rs | 12 +- .../src/solve/eval_ctxt/mod.rs | 191 +++++++----------- .../src/solve/inspect/build.rs | 14 -- compiler/rustc_type_ir/src/inherent.rs | 8 + .../as_expression.next.stderr | 11 +- .../do_not_recommend/as_expression.rs | 2 +- .../normalize/eager-norm-pre-normalizes-to.rs | 44 ++++ .../normalize-allow-too-many-vars.rs | 1 + .../issue-84660-unsoundness.rs | 2 +- 13 files changed, 155 insertions(+), 152 deletions(-) create mode 100644 tests/ui/traits/next-solver/normalize/eager-norm-pre-normalizes-to.rs diff --git a/Cargo.lock b/Cargo.lock index cfdd873e80fa..ee6726eae514 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4158,7 +4158,6 @@ dependencies = [ "rustc_data_structures", "rustc_index", "rustc_macros", - "rustc_serialize", "rustc_type_ir", "rustc_type_ir_macros", "tracing", diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index 02e316dfc3db..551d816941b6 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -121,11 +121,10 @@ impl<'tcx> Predicate<'tcx> { /// unsoundly accept some programs. See #91068. #[inline] pub fn allow_normalization(self) -> bool { - // Keep this in sync with the one in `rustc_type_ir::inherent`! match self.kind().skip_binder() { - PredicateKind::Clause(ClauseKind::WellFormed(_)) - | PredicateKind::AliasRelate(..) - | PredicateKind::NormalizesTo(..) => false, + PredicateKind::Clause(ClauseKind::WellFormed(_)) | PredicateKind::AliasRelate(..) => { + false + } PredicateKind::Clause(ClauseKind::Trait(_)) | PredicateKind::Clause(ClauseKind::HostEffect(..)) | PredicateKind::Clause(ClauseKind::RegionOutlives(_)) @@ -137,6 +136,7 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::Coerce(_) | PredicateKind::Clause(ClauseKind::ConstEvaluatable(_)) | PredicateKind::ConstEquate(_, _) + | PredicateKind::NormalizesTo(..) | PredicateKind::Ambiguous => true, } } diff --git a/compiler/rustc_next_trait_solver/Cargo.toml b/compiler/rustc_next_trait_solver/Cargo.toml index 63aa60f2f26b..36d53901d9e8 100644 --- a/compiler/rustc_next_trait_solver/Cargo.toml +++ b/compiler/rustc_next_trait_solver/Cargo.toml @@ -9,7 +9,6 @@ derive-where = "1.2.7" rustc_data_structures = { path = "../rustc_data_structures", optional = true } rustc_index = { path = "../rustc_index", default-features = false } rustc_macros = { path = "../rustc_macros", optional = true } -rustc_serialize = { path = "../rustc_serialize", optional = true } rustc_type_ir = { path = "../rustc_type_ir", default-features = false } rustc_type_ir_macros = { path = "../rustc_type_ir_macros" } tracing = "0.1" @@ -20,7 +19,6 @@ default = ["nightly"] nightly = [ "dep:rustc_data_structures", "dep:rustc_macros", - "dep:rustc_serialize", "rustc_index/nightly", "rustc_type_ir/nightly", ] diff --git a/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs b/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs index 0fc313e33b32..f7bd46009432 100644 --- a/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs +++ b/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs @@ -16,6 +16,7 @@ //! relate them structurally. use rustc_type_ir::inherent::*; +use rustc_type_ir::solve::GoalSource; use rustc_type_ir::{self as ty, Interner}; use tracing::{instrument, trace}; @@ -49,7 +50,10 @@ where // Structurally normalize the lhs. let lhs = if let Some(alias) = lhs.to_alias_term() { let term = self.next_term_infer_of_kind(lhs); - self.add_normalizes_to_goal(goal.with(cx, ty::NormalizesTo { alias, term })); + self.add_goal( + GoalSource::TypeRelating, + goal.with(cx, ty::NormalizesTo { alias, term }), + ); term } else { lhs @@ -58,7 +62,10 @@ where // Structurally normalize the rhs. let rhs = if let Some(alias) = rhs.to_alias_term() { let term = self.next_term_infer_of_kind(rhs); - self.add_normalizes_to_goal(goal.with(cx, ty::NormalizesTo { alias, term })); + self.add_goal( + GoalSource::TypeRelating, + goal.with(cx, ty::NormalizesTo { alias, term }), + ); term } else { rhs diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index d56b0e5847e5..04f80a056f94 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -22,7 +22,7 @@ use tracing::{debug, instrument, trace}; use crate::canonicalizer::Canonicalizer; use crate::delegate::SolverDelegate; use crate::resolve::EagerResolver; -use crate::solve::eval_ctxt::{CurrentGoalKind, NestedGoals}; +use crate::solve::eval_ctxt::CurrentGoalKind; use crate::solve::{ CanonicalInput, CanonicalResponse, Certainty, EvalCtxt, ExternalConstraintsData, Goal, MaybeCause, NestedNormalizationGoals, NoSolution, PredefinedOpaquesData, QueryInput, @@ -112,13 +112,9 @@ where // by `try_evaluate_added_goals()`. let (certainty, normalization_nested_goals) = match self.current_goal_kind { CurrentGoalKind::NormalizesTo => { - let NestedGoals { normalizes_to_goals, goals } = - std::mem::take(&mut self.nested_goals); - if cfg!(debug_assertions) { - assert!(normalizes_to_goals.is_empty()); - if goals.is_empty() { - assert!(matches!(goals_certainty, Certainty::Yes)); - } + let goals = std::mem::take(&mut self.nested_goals); + if goals.is_empty() { + assert!(matches!(goals_certainty, Certainty::Yes)); } (certainty, NestedNormalizationGoals(goals)) } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 9994c85d0d0d..27ca8787db5c 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -1,8 +1,8 @@ +use std::mem; use std::ops::ControlFlow; -use derive_where::derive_where; #[cfg(feature = "nightly")] -use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; +use rustc_macros::HashStable_NoContext; use rustc_type_ir::data_structures::{HashMap, HashSet, ensure_sufficient_stack}; use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::inherent::*; @@ -14,7 +14,6 @@ use rustc_type_ir::{ TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, }; -use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use tracing::{instrument, trace}; use crate::coherence; @@ -114,7 +113,7 @@ where pub(super) search_graph: &'a mut SearchGraph, - nested_goals: NestedGoals, + nested_goals: Vec<(GoalSource, Goal)>, pub(super) origin_span: I::Span, @@ -129,38 +128,6 @@ where pub(super) inspect: ProofTreeBuilder, } -#[derive_where(Clone, Debug, Default; I: Interner)] -#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] -#[cfg_attr( - feature = "nightly", - derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) -)] -struct NestedGoals { - /// These normalizes-to goals are treated specially during the evaluation - /// loop. In each iteration we take the RHS of the projection, replace it with - /// a fresh inference variable, and only after evaluating that goal do we - /// equate the fresh inference variable with the actual RHS of the predicate. - /// - /// This is both to improve caching, and to avoid using the RHS of the - /// projection predicate to influence the normalizes-to candidate we select. - /// - /// Forgetting to replace the RHS with a fresh inference variable when we evaluate - /// this goal results in an ICE.. - pub normalizes_to_goals: Vec>>, - /// The rest of the goals which have not yet processed or remain ambiguous. - pub goals: Vec<(GoalSource, Goal)>, -} - -impl NestedGoals { - fn new() -> Self { - Self { normalizes_to_goals: Vec::new(), goals: Vec::new() } - } - - fn is_empty(&self) -> bool { - self.normalizes_to_goals.is_empty() && self.goals.is_empty() - } -} - #[derive(PartialEq, Eq, Debug, Hash, Clone, Copy)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub enum GenerateProofTree { @@ -332,7 +299,7 @@ where let mut ecx = EvalCtxt { delegate, search_graph: &mut search_graph, - nested_goals: NestedGoals::new(), + nested_goals: Default::default(), inspect: ProofTreeBuilder::new_maybe_root(generate_proof_tree), // Only relevant when canonicalizing the response, @@ -385,7 +352,7 @@ where predefined_opaques_in_body: input.predefined_opaques_in_body, max_input_universe: canonical_input.canonical.max_universe, search_graph, - nested_goals: NestedGoals::new(), + nested_goals: Default::default(), origin_span: I::Span::dummy(), tainted: Ok(()), inspect: canonical_goal_evaluation.new_goal_evaluation_step(var_values), @@ -629,78 +596,83 @@ where /// Goals for the next step get directly added to the nested goals of the `EvalCtxt`. fn evaluate_added_goals_step(&mut self) -> Result, NoSolution> { let cx = self.cx(); - let mut goals = core::mem::take(&mut self.nested_goals); - // If this loop did not result in any progress, what's our final certainty. let mut unchanged_certainty = Some(Certainty::Yes); - for goal in goals.normalizes_to_goals { - // Replace the goal with an unconstrained infer var, so the - // RHS does not affect projection candidate assembly. - let unconstrained_rhs = self.next_term_infer_of_kind(goal.predicate.term); - let unconstrained_goal = goal.with( - cx, - ty::NormalizesTo { alias: goal.predicate.alias, term: unconstrained_rhs }, - ); - - let (NestedNormalizationGoals(nested_goals), _, certainty) = self.evaluate_goal_raw( - GoalEvaluationKind::Nested, - GoalSource::TypeRelating, - unconstrained_goal, - )?; - // Add the nested goals from normalization to our own nested goals. - trace!(?nested_goals); - goals.goals.extend(nested_goals); - - // Finally, equate the goal's RHS with the unconstrained var. + for (source, goal) in mem::take(&mut self.nested_goals) { + // We treat normalizes-to goals specially here. In each iteration we take the + // RHS of the projection, replace it with a fresh inference variable, and only + // after evaluating that goal do we equate the fresh inference variable with the + // actual RHS of the predicate. // - // SUBTLE: - // We structurally relate aliases here. This is necessary - // as we otherwise emit a nested `AliasRelate` goal in case the - // returned term is a rigid alias, resulting in overflow. + // This is both to improve caching, and to avoid using the RHS of the + // projection predicate to influence the normalizes-to candidate we select. // - // It is correct as both `goal.predicate.term` and `unconstrained_rhs` - // start out as an unconstrained inference variable so any aliases get - // fully normalized when instantiating it. - // - // FIXME: Strictly speaking this may be incomplete if the normalized-to - // type contains an ambiguous alias referencing bound regions. We should - // consider changing this to only use "shallow structural equality". - self.eq_structurally_relating_aliases( - goal.param_env, - goal.predicate.term, - unconstrained_rhs, - )?; - - // We only look at the `projection_ty` part here rather than - // looking at the "has changed" return from evaluate_goal, - // because we expect the `unconstrained_rhs` part of the predicate - // to have changed -- that means we actually normalized successfully! - let with_resolved_vars = self.resolve_vars_if_possible(goal); - if goal.predicate.alias != with_resolved_vars.predicate.alias { - unchanged_certainty = None; - } - - match certainty { - Certainty::Yes => {} - Certainty::Maybe(_) => { - self.nested_goals.normalizes_to_goals.push(with_resolved_vars); - unchanged_certainty = unchanged_certainty.map(|c| c.unify_with(certainty)); + // Forgetting to replace the RHS with a fresh inference variable when we evaluate + // this goal results in an ICE. + if let Some(pred) = goal.predicate.as_normalizes_to() { + // We should never encounter higher-ranked normalizes-to goals. + let pred = pred.no_bound_vars().unwrap(); + // Replace the goal with an unconstrained infer var, so the + // RHS does not affect projection candidate assembly. + let unconstrained_rhs = self.next_term_infer_of_kind(pred.term); + let unconstrained_goal = + goal.with(cx, ty::NormalizesTo { alias: pred.alias, term: unconstrained_rhs }); + + let (NestedNormalizationGoals(nested_goals), _, certainty) = + self.evaluate_goal_raw(GoalEvaluationKind::Nested, source, unconstrained_goal)?; + // Add the nested goals from normalization to our own nested goals. + trace!(?nested_goals); + self.nested_goals.extend(nested_goals); + + // Finally, equate the goal's RHS with the unconstrained var. + // + // SUBTLE: + // We structurally relate aliases here. This is necessary + // as we otherwise emit a nested `AliasRelate` goal in case the + // returned term is a rigid alias, resulting in overflow. + // + // It is correct as both `goal.predicate.term` and `unconstrained_rhs` + // start out as an unconstrained inference variable so any aliases get + // fully normalized when instantiating it. + // + // FIXME: Strictly speaking this may be incomplete if the normalized-to + // type contains an ambiguous alias referencing bound regions. We should + // consider changing this to only use "shallow structural equality". + self.eq_structurally_relating_aliases( + goal.param_env, + pred.term, + unconstrained_rhs, + )?; + + // We only look at the `projection_ty` part here rather than + // looking at the "has changed" return from evaluate_goal, + // because we expect the `unconstrained_rhs` part of the predicate + // to have changed -- that means we actually normalized successfully! + let with_resolved_vars = self.resolve_vars_if_possible(goal); + if pred.alias != goal.predicate.as_normalizes_to().unwrap().skip_binder().alias { + unchanged_certainty = None; } - } - } - for (source, goal) in goals.goals { - let (has_changed, certainty) = - self.evaluate_goal(GoalEvaluationKind::Nested, source, goal)?; - if has_changed == HasChanged::Yes { - unchanged_certainty = None; - } + match certainty { + Certainty::Yes => {} + Certainty::Maybe(_) => { + self.nested_goals.push((source, with_resolved_vars)); + unchanged_certainty = unchanged_certainty.map(|c| c.unify_with(certainty)); + } + } + } else { + let (has_changed, certainty) = + self.evaluate_goal(GoalEvaluationKind::Nested, source, goal)?; + if has_changed == HasChanged::Yes { + unchanged_certainty = None; + } - match certainty { - Certainty::Yes => {} - Certainty::Maybe(_) => { - self.nested_goals.goals.push((source, goal)); - unchanged_certainty = unchanged_certainty.map(|c| c.unify_with(certainty)); + match certainty { + Certainty::Yes => {} + Certainty::Maybe(_) => { + self.nested_goals.push((source, goal)); + unchanged_certainty = unchanged_certainty.map(|c| c.unify_with(certainty)); + } } } } @@ -717,23 +689,12 @@ where self.delegate.cx() } - #[instrument(level = "trace", skip(self))] - pub(super) fn add_normalizes_to_goal(&mut self, mut goal: Goal>) { - goal.predicate = goal.predicate.fold_with(&mut ReplaceAliasWithInfer::new( - self, - GoalSource::TypeRelating, - goal.param_env, - )); - self.inspect.add_normalizes_to_goal(self.delegate, self.max_input_universe, goal); - self.nested_goals.normalizes_to_goals.push(goal); - } - #[instrument(level = "debug", skip(self))] pub(super) fn add_goal(&mut self, source: GoalSource, mut goal: Goal) { goal.predicate = goal.predicate.fold_with(&mut ReplaceAliasWithInfer::new(self, source, goal.param_env)); self.inspect.add_goal(self.delegate, self.max_input_universe, source, goal); - self.nested_goals.goals.push((source, goal)); + self.nested_goals.push((source, goal)); } #[instrument(level = "trace", skip(self, goals))] diff --git a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs index 6a8e0790f7cb..f22b275bc44a 100644 --- a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs +++ b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs @@ -412,20 +412,6 @@ impl, I: Interner> ProofTreeBuilder { } } - pub(crate) fn add_normalizes_to_goal( - &mut self, - delegate: &D, - max_input_universe: ty::UniverseIndex, - goal: Goal>, - ) { - self.add_goal( - delegate, - max_input_universe, - GoalSource::TypeRelating, - goal.with(delegate.cx(), goal.predicate), - ); - } - pub(crate) fn add_goal( &mut self, delegate: &D, diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 417803e75ead..9b066b6869f5 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -442,6 +442,14 @@ pub trait Predicate>: { fn as_clause(self) -> Option; + fn as_normalizes_to(self) -> Option>> { + let kind = self.kind(); + match kind.skip_binder() { + ty::PredicateKind::NormalizesTo(pred) => Some(kind.rebind(pred)), + _ => None, + } + } + // FIXME: Eventually uplift the impl out of rustc and make this defaulted. fn allow_normalization(self) -> bool; } diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr index 6170250992ce..8178f54b2aab 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr +++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr @@ -18,13 +18,16 @@ LL | where LL | T: AsExpression, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::check` -error[E0271]: type mismatch resolving `Integer == Text` +error[E0277]: the trait bound `&str: AsExpression` is not satisfied --> $DIR/as_expression.rs:56:5 | LL | SelectInt.check("bar"); - | ^^^^^^^^^^^^^^^^^^^^^^ types differ + | ^^^^^^^^^^^^^^^^^^^^^^ the trait `AsExpression` is not implemented for `&str` + | + = help: the trait `AsExpression` is not implemented for `&str` + but trait `AsExpression` is implemented for it + = help: for that trait implementation, expected `Text`, found `Integer` error: aborting due to 2 previous errors -Some errors have detailed explanations: E0271, E0277. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs index 673adb82870d..86f39e43484e 100644 --- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs +++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs @@ -55,5 +55,5 @@ impl Foo for T where T: Expression {} fn main() { SelectInt.check("bar"); //~^ ERROR the trait bound `&str: AsExpression` is not satisfied - //[next]~| ERROR type mismatch + //[next]~| ERROR the trait bound `&str: AsExpression` is not satisfied } diff --git a/tests/ui/traits/next-solver/normalize/eager-norm-pre-normalizes-to.rs b/tests/ui/traits/next-solver/normalize/eager-norm-pre-normalizes-to.rs new file mode 100644 index 000000000000..ea18ac54c055 --- /dev/null +++ b/tests/ui/traits/next-solver/normalize/eager-norm-pre-normalizes-to.rs @@ -0,0 +1,44 @@ +//@ check-pass +//@ compile-flags: -Znext-solver + +// A regression test for trait-system-refactor-initiative#184. +// +// When adding nested goals we replace aliases with infer vars +// and add `AliasRelate` goals to constrain them. When doing this +// for `NormalizesTo` goals, we then first tries to prove the +// `NormalizesTo` goal and then normalized the nested aliases. + +trait Trait { + type Assoc; +} +impl Trait for T { + type Assoc = (); +} + +trait Id { + type This; +} +impl Id for T { + type This = T; +} +trait Relate { + type Alias; +} +impl Relate for T { + type Alias = ::This>>::Assoc; +} + + +fn guide_me>() { + // Normalizing `>::Alias` relates the associated type with an unconstrained + // term. This resulted in a `NormalizesTo(::This>>::Assoc, ?x)` goal. + // We replace `::This` with an infer var `?y`, resulting in the following goals: + // - `NormalizesTo(::Assoc, ?x)` + // - `AliasRelate(::This, ?y)` + // + // When proving the `NormalizesTo` goal first, we incompletely constrain `?y` to `u32`, + // causing an unexpected type mismatch. + let _: >::Alias; +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/normalize/normalize-allow-too-many-vars.rs b/tests/ui/traits/next-solver/normalize/normalize-allow-too-many-vars.rs index 5284220ac38f..3150d9a88d0e 100644 --- a/tests/ui/traits/next-solver/normalize/normalize-allow-too-many-vars.rs +++ b/tests/ui/traits/next-solver/normalize/normalize-allow-too-many-vars.rs @@ -1,4 +1,5 @@ //@ check-pass +//@ compile-flags: -Znext-solver // When canonicalizing a response in the trait solver, we bail with overflow // if there are too many non-region inference variables. Doing so in normalizes-to diff --git a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.rs b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.rs index 4391bf01dc91..7a540d2a5749 100644 --- a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.rs +++ b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.rs @@ -22,7 +22,7 @@ impl Trait for Out { type Out = Out; #[define_opaque(Bar)] fn convert(_i: In) -> Self::Out { - //[next]~^ ERROR: cannot satisfy `Bar == _` + //[next]~^ ERROR: type annotations needed: cannot satisfy `Bar == _` //[current]~^^ ERROR: item does not constrain `Bar::{opaque#0}` unreachable!(); } From 75a9be609ed3f932b9c1f15a18c8afbf41138893 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 26 Feb 2025 04:25:21 +0000 Subject: [PATCH 16/17] Deprecate the unstable `concat_idents!` `concat_idents` has been around unstably for a long time, but there is now a better (but still unstable) way to join identifiers using `${concat(...)}` syntax with `macro_metavar_expr_concat`. This resolves a lot of the problems with `concat_idents` and is on a better track toward stabilization, so there is no need to keep both versions around. `concat_idents!` still has a lot of use in the ecosystem so deprecate it before removing, as discussed in [1]. Link: https://github.com/rust-lang/rust/issues/124225 [1]: https://rust-lang.zulipchat.com/#narrow/channel/219381-t-libs/topic/Removing.20.60concat_idents.60 --- library/core/src/macros/mod.rs | 4 ++ library/core/src/prelude/v1.rs | 1 + library/std/src/lib.rs | 1 + library/std/src/prelude/v1.rs | 1 + .../src/library-features/concat-idents.md | 3 + .../feature-gate-concat_idents.rs | 2 + .../feature-gate-concat_idents.stderr | 4 +- .../feature-gate-concat_idents2.rs | 2 + .../feature-gate-concat_idents2.stderr | 4 +- .../feature-gate-concat_idents3.rs | 2 + .../feature-gate-concat_idents3.stderr | 4 +- tests/ui/issues/issue-32950.rs | 1 + tests/ui/issues/issue-32950.stderr | 4 +- tests/ui/issues/issue-50403.rs | 1 + tests/ui/issues/issue-50403.stderr | 2 +- tests/ui/macros/macros-nonfatal-errors.rs | 1 + tests/ui/macros/macros-nonfatal-errors.stderr | 62 +++++++++---------- .../simd/intrinsic/generic-comparison-pass.rs | 4 +- tests/ui/syntax-extension-minor.rs | 1 + tests/ui/unpretty/expanded-exhaustive.rs | 1 + tests/ui/unpretty/expanded-exhaustive.stdout | 2 + 21 files changed, 65 insertions(+), 42 deletions(-) diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 330b40987645..16c0c1180404 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1138,6 +1138,10 @@ pub(crate) mod builtin { issue = "29599", reason = "`concat_idents` is not stable enough for use and is subject to change" )] + #[deprecated( + since = "1.88.0", + note = "use `${concat(...)}` with the `macro_metavar_expr_concat` feature instead" + )] #[rustc_builtin_macro] #[macro_export] macro_rules! concat_idents { diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs index 8f1b5275871e..9737d0baec7c 100644 --- a/library/core/src/prelude/v1.rs +++ b/library/core/src/prelude/v1.rs @@ -59,6 +59,7 @@ pub use crate::hash::macros::Hash; #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] #[allow(deprecated)] +#[cfg_attr(bootstrap, allow(deprecated_in_future))] #[doc(no_inline)] pub use crate::{ assert, cfg, column, compile_error, concat, concat_idents, env, file, format_args, diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 3a52b7790376..f77bf92a806e 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -709,6 +709,7 @@ pub use core::primitive; // Re-export built-in macros defined through core. #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] #[allow(deprecated)] +#[cfg_attr(bootstrap, allow(deprecated_in_future))] pub use core::{ assert, assert_matches, cfg, column, compile_error, concat, concat_idents, const_format_args, env, file, format_args, format_args_nl, include, include_bytes, include_str, line, log_syntax, diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs index c15d8c40085a..68c9ac1e4146 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/v1.rs @@ -46,6 +46,7 @@ pub use crate::result::Result::{self, Err, Ok}; // Re-exported built-in macros #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] #[allow(deprecated)] +#[cfg_attr(bootstrap, allow(deprecated_in_future))] #[doc(no_inline)] pub use core::prelude::v1::{ assert, cfg, column, compile_error, concat, concat_idents, env, file, format_args, diff --git a/src/doc/unstable-book/src/library-features/concat-idents.md b/src/doc/unstable-book/src/library-features/concat-idents.md index 4366172fb996..8a38d155e3db 100644 --- a/src/doc/unstable-book/src/library-features/concat-idents.md +++ b/src/doc/unstable-book/src/library-features/concat-idents.md @@ -2,7 +2,10 @@ The tracking issue for this feature is: [#29599] +This feature is deprecated, to be replaced by [`macro_metavar_expr_concat`]. + [#29599]: https://github.com/rust-lang/rust/issues/29599 +[`macro_metavar_expr_concat`]: https://github.com/rust-lang/rust/issues/124225 ------------------------ diff --git a/tests/ui/feature-gates/feature-gate-concat_idents.rs b/tests/ui/feature-gates/feature-gate-concat_idents.rs index 68caf3d71e90..4fc3b6915973 100644 --- a/tests/ui/feature-gates/feature-gate-concat_idents.rs +++ b/tests/ui/feature-gates/feature-gate-concat_idents.rs @@ -1,3 +1,5 @@ +#![expect(deprecated)] // concat_idents is deprecated + const XY_1: i32 = 10; fn main() { diff --git a/tests/ui/feature-gates/feature-gate-concat_idents.stderr b/tests/ui/feature-gates/feature-gate-concat_idents.stderr index d0f4fe62d048..6399424eecd8 100644 --- a/tests/ui/feature-gates/feature-gate-concat_idents.stderr +++ b/tests/ui/feature-gates/feature-gate-concat_idents.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature `concat_idents`: `concat_idents` is not stable enough for use and is subject to change - --> $DIR/feature-gate-concat_idents.rs:5:13 + --> $DIR/feature-gate-concat_idents.rs:7:13 | LL | let a = concat_idents!(X, Y_1); | ^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | let a = concat_idents!(X, Y_1); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature `concat_idents`: `concat_idents` is not stable enough for use and is subject to change - --> $DIR/feature-gate-concat_idents.rs:6:13 + --> $DIR/feature-gate-concat_idents.rs:8:13 | LL | let b = concat_idents!(X, Y_2); | ^^^^^^^^^^^^^ diff --git a/tests/ui/feature-gates/feature-gate-concat_idents2.rs b/tests/ui/feature-gates/feature-gate-concat_idents2.rs index 9660ffeafa51..bc2b4f7cddf9 100644 --- a/tests/ui/feature-gates/feature-gate-concat_idents2.rs +++ b/tests/ui/feature-gates/feature-gate-concat_idents2.rs @@ -1,3 +1,5 @@ +#![expect(deprecated)] // concat_idents is deprecated + fn main() { concat_idents!(a, b); //~ ERROR `concat_idents` is not stable enough //~| ERROR cannot find value `ab` in this scope diff --git a/tests/ui/feature-gates/feature-gate-concat_idents2.stderr b/tests/ui/feature-gates/feature-gate-concat_idents2.stderr index b42a1d999e4d..a770c1a348b5 100644 --- a/tests/ui/feature-gates/feature-gate-concat_idents2.stderr +++ b/tests/ui/feature-gates/feature-gate-concat_idents2.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature `concat_idents`: `concat_idents` is not stable enough for use and is subject to change - --> $DIR/feature-gate-concat_idents2.rs:2:5 + --> $DIR/feature-gate-concat_idents2.rs:4:5 | LL | concat_idents!(a, b); | ^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | concat_idents!(a, b); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0425]: cannot find value `ab` in this scope - --> $DIR/feature-gate-concat_idents2.rs:2:5 + --> $DIR/feature-gate-concat_idents2.rs:4:5 | LL | concat_idents!(a, b); | ^^^^^^^^^^^^^^^^^^^^ not found in this scope diff --git a/tests/ui/feature-gates/feature-gate-concat_idents3.rs b/tests/ui/feature-gates/feature-gate-concat_idents3.rs index 81710fd9fb04..d4a0d2e6bb0e 100644 --- a/tests/ui/feature-gates/feature-gate-concat_idents3.rs +++ b/tests/ui/feature-gates/feature-gate-concat_idents3.rs @@ -1,3 +1,5 @@ +#![expect(deprecated)] // concat_idents is deprecated + const XY_1: i32 = 10; fn main() { diff --git a/tests/ui/feature-gates/feature-gate-concat_idents3.stderr b/tests/ui/feature-gates/feature-gate-concat_idents3.stderr index b186601d0ed6..7d929322bc06 100644 --- a/tests/ui/feature-gates/feature-gate-concat_idents3.stderr +++ b/tests/ui/feature-gates/feature-gate-concat_idents3.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature `concat_idents`: `concat_idents` is not stable enough for use and is subject to change - --> $DIR/feature-gate-concat_idents3.rs:5:20 + --> $DIR/feature-gate-concat_idents3.rs:7:20 | LL | assert_eq!(10, concat_idents!(X, Y_1)); | ^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | assert_eq!(10, concat_idents!(X, Y_1)); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: use of unstable library feature `concat_idents`: `concat_idents` is not stable enough for use and is subject to change - --> $DIR/feature-gate-concat_idents3.rs:6:20 + --> $DIR/feature-gate-concat_idents3.rs:8:20 | LL | assert_eq!(20, concat_idents!(X, Y_2)); | ^^^^^^^^^^^^^ diff --git a/tests/ui/issues/issue-32950.rs b/tests/ui/issues/issue-32950.rs index 27d68a11c1f1..b51ac2967768 100644 --- a/tests/ui/issues/issue-32950.rs +++ b/tests/ui/issues/issue-32950.rs @@ -1,4 +1,5 @@ #![feature(concat_idents)] +#![expect(deprecated)] // concat_idents is deprecated #[derive(Debug)] struct Baz( diff --git a/tests/ui/issues/issue-32950.stderr b/tests/ui/issues/issue-32950.stderr index 3cdf35af1d86..38a82542f896 100644 --- a/tests/ui/issues/issue-32950.stderr +++ b/tests/ui/issues/issue-32950.stderr @@ -1,11 +1,11 @@ error: `derive` cannot be used on items with type macros - --> $DIR/issue-32950.rs:5:5 + --> $DIR/issue-32950.rs:6:5 | LL | concat_idents!(Foo, Bar) | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0412]: cannot find type `FooBar` in this scope - --> $DIR/issue-32950.rs:5:5 + --> $DIR/issue-32950.rs:6:5 | LL | concat_idents!(Foo, Bar) | ^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope diff --git a/tests/ui/issues/issue-50403.rs b/tests/ui/issues/issue-50403.rs index ab22aff26d99..f14958afc34d 100644 --- a/tests/ui/issues/issue-50403.rs +++ b/tests/ui/issues/issue-50403.rs @@ -1,4 +1,5 @@ #![feature(concat_idents)] +#![expect(deprecated)] // concat_idents is deprecated fn main() { let x = concat_idents!(); //~ ERROR `concat_idents!()` takes 1 or more arguments diff --git a/tests/ui/issues/issue-50403.stderr b/tests/ui/issues/issue-50403.stderr index 193d815d5195..e7dd05bb0183 100644 --- a/tests/ui/issues/issue-50403.stderr +++ b/tests/ui/issues/issue-50403.stderr @@ -1,5 +1,5 @@ error: `concat_idents!()` takes 1 or more arguments - --> $DIR/issue-50403.rs:4:13 + --> $DIR/issue-50403.rs:5:13 | LL | let x = concat_idents!(); | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/macros/macros-nonfatal-errors.rs b/tests/ui/macros/macros-nonfatal-errors.rs index 79beffbe986e..091d64ea5d9e 100644 --- a/tests/ui/macros/macros-nonfatal-errors.rs +++ b/tests/ui/macros/macros-nonfatal-errors.rs @@ -5,6 +5,7 @@ #![feature(trace_macros, concat_idents)] #![feature(stmt_expr_attributes)] +#![expect(deprecated)] // concat_idents is deprecated use std::arch::asm; diff --git a/tests/ui/macros/macros-nonfatal-errors.stderr b/tests/ui/macros/macros-nonfatal-errors.stderr index 44194b506a43..2f990cb24e2b 100644 --- a/tests/ui/macros/macros-nonfatal-errors.stderr +++ b/tests/ui/macros/macros-nonfatal-errors.stderr @@ -1,5 +1,5 @@ error: the `#[default]` attribute may only be used on unit enum variants - --> $DIR/macros-nonfatal-errors.rs:13:5 + --> $DIR/macros-nonfatal-errors.rs:14:5 | LL | #[default] | ^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | #[default] = help: consider a manual implementation of `Default` error: the `#[default]` attribute may only be used on unit enum variants - --> $DIR/macros-nonfatal-errors.rs:18:36 + --> $DIR/macros-nonfatal-errors.rs:19:36 | LL | struct DefaultInnerAttrTupleStruct(#[default] ()); | ^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | struct DefaultInnerAttrTupleStruct(#[default] ()); = help: consider a manual implementation of `Default` error: the `#[default]` attribute may only be used on unit enum variants - --> $DIR/macros-nonfatal-errors.rs:22:1 + --> $DIR/macros-nonfatal-errors.rs:23:1 | LL | #[default] | ^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | #[default] = help: consider a manual implementation of `Default` error: the `#[default]` attribute may only be used on unit enum variants - --> $DIR/macros-nonfatal-errors.rs:26:1 + --> $DIR/macros-nonfatal-errors.rs:27:1 | LL | #[default] | ^^^^^^^^^^ @@ -31,7 +31,7 @@ LL | #[default] = help: consider a manual implementation of `Default` error: the `#[default]` attribute may only be used on unit enum variants - --> $DIR/macros-nonfatal-errors.rs:36:11 + --> $DIR/macros-nonfatal-errors.rs:37:11 | LL | Foo = #[default] 0, | ^^^^^^^^^^ @@ -39,7 +39,7 @@ LL | Foo = #[default] 0, = help: consider a manual implementation of `Default` error: the `#[default]` attribute may only be used on unit enum variants - --> $DIR/macros-nonfatal-errors.rs:37:14 + --> $DIR/macros-nonfatal-errors.rs:38:14 | LL | Bar([u8; #[default] 1]), | ^^^^^^^^^^ @@ -47,7 +47,7 @@ LL | Bar([u8; #[default] 1]), = help: consider a manual implementation of `Default` error[E0665]: `#[derive(Default)]` on enum with no `#[default]` - --> $DIR/macros-nonfatal-errors.rs:42:10 + --> $DIR/macros-nonfatal-errors.rs:43:10 | LL | #[derive(Default)] | ^^^^^^^ @@ -67,7 +67,7 @@ LL | #[default] Bar, | ++++++++++ error[E0665]: `#[derive(Default)]` on enum with no `#[default]` - --> $DIR/macros-nonfatal-errors.rs:48:10 + --> $DIR/macros-nonfatal-errors.rs:49:10 | LL | #[derive(Default)] | ^^^^^^^ @@ -78,7 +78,7 @@ LL | | } | |_- this enum needs a unit variant marked with `#[default]` error: multiple declared defaults - --> $DIR/macros-nonfatal-errors.rs:54:10 + --> $DIR/macros-nonfatal-errors.rs:55:10 | LL | #[derive(Default)] | ^^^^^^^ @@ -95,7 +95,7 @@ LL | Baz, = note: only one variant can be default error: `#[default]` attribute does not accept a value - --> $DIR/macros-nonfatal-errors.rs:66:5 + --> $DIR/macros-nonfatal-errors.rs:67:5 | LL | #[default = 1] | ^^^^^^^^^^^^^^ @@ -103,7 +103,7 @@ LL | #[default = 1] = help: try using `#[default]` error: multiple `#[default]` attributes - --> $DIR/macros-nonfatal-errors.rs:74:5 + --> $DIR/macros-nonfatal-errors.rs:75:5 | LL | #[default] | ---------- `#[default]` used here @@ -114,13 +114,13 @@ LL | Foo, | = note: only one `#[default]` attribute is needed help: try removing this - --> $DIR/macros-nonfatal-errors.rs:73:5 + --> $DIR/macros-nonfatal-errors.rs:74:5 | LL | #[default] | ^^^^^^^^^^ error: multiple `#[default]` attributes - --> $DIR/macros-nonfatal-errors.rs:84:5 + --> $DIR/macros-nonfatal-errors.rs:85:5 | LL | #[default] | ---------- `#[default]` used here @@ -132,7 +132,7 @@ LL | Foo, | = note: only one `#[default]` attribute is needed help: try removing these - --> $DIR/macros-nonfatal-errors.rs:81:5 + --> $DIR/macros-nonfatal-errors.rs:82:5 | LL | #[default] | ^^^^^^^^^^ @@ -142,7 +142,7 @@ LL | #[default] | ^^^^^^^^^^ error: the `#[default]` attribute may only be used on unit enum variants - --> $DIR/macros-nonfatal-errors.rs:91:5 + --> $DIR/macros-nonfatal-errors.rs:92:5 | LL | Foo {}, | ^^^ @@ -150,7 +150,7 @@ LL | Foo {}, = help: consider a manual implementation of `Default` error: default variant must be exhaustive - --> $DIR/macros-nonfatal-errors.rs:99:5 + --> $DIR/macros-nonfatal-errors.rs:100:5 | LL | #[non_exhaustive] | ----------------- declared `#[non_exhaustive]` here @@ -160,37 +160,37 @@ LL | Foo, = help: consider a manual implementation of `Default` error: asm template must be a string literal - --> $DIR/macros-nonfatal-errors.rs:104:10 + --> $DIR/macros-nonfatal-errors.rs:105:10 | LL | asm!(invalid); | ^^^^^^^ error: `concat_idents!()` requires ident args - --> $DIR/macros-nonfatal-errors.rs:107:5 + --> $DIR/macros-nonfatal-errors.rs:108:5 | LL | concat_idents!("not", "idents"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: argument must be a string literal - --> $DIR/macros-nonfatal-errors.rs:109:17 + --> $DIR/macros-nonfatal-errors.rs:110:17 | LL | option_env!(invalid); | ^^^^^^^ error: expected string literal - --> $DIR/macros-nonfatal-errors.rs:110:10 + --> $DIR/macros-nonfatal-errors.rs:111:10 | LL | env!(invalid); | ^^^^^^^ error: `env!()` takes 1 or 2 arguments - --> $DIR/macros-nonfatal-errors.rs:111:5 + --> $DIR/macros-nonfatal-errors.rs:112:5 | LL | env!(foo, abr, baz); | ^^^^^^^^^^^^^^^^^^^ error: environment variable `RUST_HOPEFULLY_THIS_DOESNT_EXIST` not defined at compile time - --> $DIR/macros-nonfatal-errors.rs:112:5 + --> $DIR/macros-nonfatal-errors.rs:113:5 | LL | env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -198,7 +198,7 @@ LL | env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST"); = help: use `std::env::var("RUST_HOPEFULLY_THIS_DOESNT_EXIST")` to read the variable at run time error: format argument must be a string literal - --> $DIR/macros-nonfatal-errors.rs:114:13 + --> $DIR/macros-nonfatal-errors.rs:115:13 | LL | format!(invalid); | ^^^^^^^ @@ -209,43 +209,43 @@ LL | format!("{}", invalid); | +++++ error: argument must be a string literal - --> $DIR/macros-nonfatal-errors.rs:116:14 + --> $DIR/macros-nonfatal-errors.rs:117:14 | LL | include!(invalid); | ^^^^^^^ error: argument must be a string literal - --> $DIR/macros-nonfatal-errors.rs:118:18 + --> $DIR/macros-nonfatal-errors.rs:119:18 | LL | include_str!(invalid); | ^^^^^^^ error: couldn't read `$DIR/i'd be quite surprised if a file with this name existed`: $FILE_NOT_FOUND_MSG - --> $DIR/macros-nonfatal-errors.rs:119:5 + --> $DIR/macros-nonfatal-errors.rs:120:5 | LL | include_str!("i'd be quite surprised if a file with this name existed"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: argument must be a string literal - --> $DIR/macros-nonfatal-errors.rs:120:20 + --> $DIR/macros-nonfatal-errors.rs:121:20 | LL | include_bytes!(invalid); | ^^^^^^^ error: couldn't read `$DIR/i'd be quite surprised if a file with this name existed`: $FILE_NOT_FOUND_MSG - --> $DIR/macros-nonfatal-errors.rs:121:5 + --> $DIR/macros-nonfatal-errors.rs:122:5 | LL | include_bytes!("i'd be quite surprised if a file with this name existed"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: trace_macros! accepts only `true` or `false` - --> $DIR/macros-nonfatal-errors.rs:123:5 + --> $DIR/macros-nonfatal-errors.rs:124:5 | LL | trace_macros!(invalid); | ^^^^^^^^^^^^^^^^^^^^^^ error: default variant must be exhaustive - --> $DIR/macros-nonfatal-errors.rs:133:9 + --> $DIR/macros-nonfatal-errors.rs:134:9 | LL | #[non_exhaustive] | ----------------- declared `#[non_exhaustive]` here @@ -255,7 +255,7 @@ LL | Foo, = help: consider a manual implementation of `Default` error: cannot find macro `llvm_asm` in this scope - --> $DIR/macros-nonfatal-errors.rs:105:5 + --> $DIR/macros-nonfatal-errors.rs:106:5 | LL | llvm_asm!(invalid); | ^^^^^^^^ diff --git a/tests/ui/simd/intrinsic/generic-comparison-pass.rs b/tests/ui/simd/intrinsic/generic-comparison-pass.rs index 2ee164cdfd80..50a05eecb03b 100644 --- a/tests/ui/simd/intrinsic/generic-comparison-pass.rs +++ b/tests/ui/simd/intrinsic/generic-comparison-pass.rs @@ -1,6 +1,6 @@ //@ run-pass -#![feature(repr_simd, core_intrinsics, concat_idents)] +#![feature(repr_simd, core_intrinsics, macro_metavar_expr_concat)] #![allow(non_camel_case_types)] use std::intrinsics::simd::{simd_eq, simd_ge, simd_gt, simd_le, simd_lt, simd_ne}; @@ -19,7 +19,7 @@ macro_rules! cmp { ($method: ident($lhs: expr, $rhs: expr)) => {{ let lhs = $lhs; let rhs = $rhs; - let e: u32x4 = concat_idents!(simd_, $method)($lhs, $rhs); + let e: u32x4 = ${concat(simd_, $method)}($lhs, $rhs); // assume the scalar version is correct/the behaviour we want. assert!((e.0[0] != 0) == lhs.0[0].$method(&rhs.0[0])); assert!((e.0[1] != 0) == lhs.0[1].$method(&rhs.0[1])); diff --git a/tests/ui/syntax-extension-minor.rs b/tests/ui/syntax-extension-minor.rs index cdd572b50fcc..826990a89a53 100644 --- a/tests/ui/syntax-extension-minor.rs +++ b/tests/ui/syntax-extension-minor.rs @@ -1,6 +1,7 @@ //@ run-pass #![feature(concat_idents)] +#![expect(deprecated)] // concat_idents is deprecated pub fn main() { struct Foo; diff --git a/tests/ui/unpretty/expanded-exhaustive.rs b/tests/ui/unpretty/expanded-exhaustive.rs index 0fb5a26c5aae..5697f615b979 100644 --- a/tests/ui/unpretty/expanded-exhaustive.rs +++ b/tests/ui/unpretty/expanded-exhaustive.rs @@ -839,6 +839,7 @@ mod types { } /// TyKind::MacCall + #[expect(deprecated)] // concat_idents is deprecated fn ty_mac_call() { let _: concat_idents!(T); let _: concat_idents![T]; diff --git a/tests/ui/unpretty/expanded-exhaustive.stdout b/tests/ui/unpretty/expanded-exhaustive.stdout index 8febd2d6d492..841edf63c919 100644 --- a/tests/ui/unpretty/expanded-exhaustive.stdout +++ b/tests/ui/unpretty/expanded-exhaustive.stdout @@ -359,6 +359,7 @@ mod expressions { + // concat_idents is deprecated @@ -674,6 +675,7 @@ mod types { /*! there is no syntax for this */ } /// TyKind::MacCall + #[expect(deprecated)] fn ty_mac_call() { let _: T; let _: T; let _: T; } /// TyKind::CVarArgs fn ty_c_var_args() { From 1d0b3be659fe7128f4a66f593729e9c0627ed90a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 25 Apr 2025 01:53:05 +0000 Subject: [PATCH 17/17] Don't use item name to look up associated item from trait item --- .../traits/fulfillment_errors.rs | 12 ++++----- .../dont-probe-missing-item-name-4.rs | 23 ++++++++++++++++ .../dont-probe-missing-item-name-4.stderr | 26 +++++++++++++++++++ 3 files changed, 54 insertions(+), 7 deletions(-) create mode 100644 tests/ui/impl-trait/in-trait/dont-probe-missing-item-name-4.rs create mode 100644 tests/ui/impl-trait/in-trait/dont-probe-missing-item-name-4.stderr diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index df6e8fc4503f..4330f1f22925 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -1523,19 +1523,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return None; }; - let trait_assoc_item = self.tcx.opt_associated_item(proj.projection_term.def_id)?; - let trait_assoc_ident = trait_assoc_item.ident(self.tcx); - let mut associated_items = vec![]; self.tcx.for_each_relevant_impl( self.tcx.trait_of_item(proj.projection_term.def_id)?, proj.projection_term.self_ty(), |impl_def_id| { associated_items.extend( - self.tcx - .associated_items(impl_def_id) - .in_definition_order() - .find(|assoc| assoc.ident(self.tcx) == trait_assoc_ident), + self.tcx.associated_items(impl_def_id).in_definition_order().find( + |assoc| { + assoc.trait_item_def_id == Some(proj.projection_term.def_id) + }, + ), ); }, ); diff --git a/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name-4.rs b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name-4.rs new file mode 100644 index 000000000000..1ee3bfd12339 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name-4.rs @@ -0,0 +1,23 @@ +trait ServerFn { + type Output; + fn run_body() -> impl Sized; +} +struct MyServerFn {} + +macro_rules! f { + () => { + impl ServerFn for MyServerFn { + type Output = (); + fn run_body() -> impl Sized {} + } + }; +} + +f! {} + +fn problem>(_: T) {} + +fn main() { + problem(MyServerFn {}); + //~^ ERROR type mismatch resolving `::Output == i64` +} diff --git a/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name-4.stderr b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name-4.stderr new file mode 100644 index 000000000000..b4c022d35219 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name-4.stderr @@ -0,0 +1,26 @@ +error[E0271]: type mismatch resolving `::Output == i64` + --> $DIR/dont-probe-missing-item-name-4.rs:21:13 + | +LL | problem(MyServerFn {}); + | ------- ^^^^^^^^^^^^^ type mismatch resolving `::Output == i64` + | | + | required by a bound introduced by this call + | +note: expected this to be `i64` + --> $DIR/dont-probe-missing-item-name-4.rs:10:27 + | +LL | type Output = (); + | ^^ +... +LL | f! {} + | ----- in this macro invocation +note: required by a bound in `problem` + --> $DIR/dont-probe-missing-item-name-4.rs:18:24 + | +LL | fn problem>(_: T) {} + | ^^^^^^^^^^^^ required by this bound in `problem` + = note: this error originates in the macro `f` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0271`.