diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f1c87b0a76e15..16b0512a88a46 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -156,7 +156,7 @@ jobs: run: src/ci/scripts/verify-stable-version-number.sh if: success() && !env.SKIP_JOB - name: run the build - run: src/ci/scripts/run-build-from-ci.sh + run: src/ci/scripts/run-build-from-ci.sh 2>&1 env: AWS_ACCESS_KEY_ID: "${{ env.CACHES_AWS_ACCESS_KEY_ID }}" AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}" @@ -566,7 +566,7 @@ jobs: run: src/ci/scripts/verify-stable-version-number.sh if: success() && !env.SKIP_JOB - name: run the build - run: src/ci/scripts/run-build-from-ci.sh + run: src/ci/scripts/run-build-from-ci.sh 2>&1 env: AWS_ACCESS_KEY_ID: "${{ env.CACHES_AWS_ACCESS_KEY_ID }}" AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}" @@ -705,7 +705,7 @@ jobs: run: src/ci/scripts/verify-stable-version-number.sh if: success() && !env.SKIP_JOB - name: run the build - run: src/ci/scripts/run-build-from-ci.sh + run: src/ci/scripts/run-build-from-ci.sh 2>&1 env: AWS_ACCESS_KEY_ID: "${{ env.CACHES_AWS_ACCESS_KEY_ID }}" AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}" diff --git a/library/core/src/cell/once.rs b/library/core/src/cell/once.rs index 3877a0c48cb23..a7c3dfc982d12 100644 --- a/library/core/src/cell/once.rs +++ b/library/core/src/cell/once.rs @@ -164,6 +164,42 @@ impl OnceCell { } } + /// Gets the mutable reference of the contents of the cell, + /// initializing it with `f` if the cell was empty. + /// + /// # Panics + /// + /// If `f` panics, the panic is propagated to the caller, and the cell + /// remains uninitialized. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell_get_mut)] + /// + /// use std::cell::OnceCell; + /// + /// let mut cell = OnceCell::new(); + /// let value = cell.get_mut_or_init(|| 92); + /// assert_eq!(*value, 92); + /// + /// *value += 2; + /// assert_eq!(*value, 94); + /// + /// let value = cell.get_mut_or_init(|| unreachable!()); + /// assert_eq!(*value, 94); + /// ``` + #[inline] + #[unstable(feature = "once_cell_get_mut", issue = "121641")] + pub fn get_mut_or_init(&mut self, f: F) -> &mut T + where + F: FnOnce() -> T, + { + match self.get_mut_or_try_init(|| Ok::(f())) { + Ok(val) => val, + } + } + /// Gets the contents of the cell, initializing it with `f` if /// the cell was empty. If the cell was empty and `f` failed, an /// error is returned. @@ -200,16 +236,55 @@ impl OnceCell { if let Some(val) = self.get() { return Ok(val); } - /// Avoid inlining the initialization closure into the common path that fetches - /// the already initialized value - #[cold] - fn outlined_call(f: F) -> Result - where - F: FnOnce() -> Result, - { - f() + self.try_init(f) + } + + /// Gets the mutable reference of the contents of the cell, initializing + /// it with `f` if the cell was empty. If the cell was empty and `f` failed, + /// an error is returned. + /// + /// # Panics + /// + /// If `f` panics, the panic is propagated to the caller, and the cell + /// remains uninitialized. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell_get_mut)] + /// + /// use std::cell::OnceCell; + /// + /// let mut cell: OnceCell = OnceCell::new(); + /// + /// // Failed initializers do not change the value + /// assert!(cell.get_mut_or_try_init(|| "not a number!".parse()).is_err()); + /// assert!(cell.get().is_none()); + /// + /// let value = cell.get_mut_or_try_init(|| "1234".parse()); + /// assert_eq!(value, Ok(&mut 1234)); + /// *value.unwrap() += 2; + /// assert_eq!(cell.get(), Some(&1236)) + /// ``` + #[unstable(feature = "once_cell_get_mut", issue = "121641")] + pub fn get_mut_or_try_init(&mut self, f: F) -> Result<&mut T, E> + where + F: FnOnce() -> Result, + { + if self.get().is_none() { + self.try_init(f)?; } - let val = outlined_call(f)?; + Ok(self.get_mut().unwrap()) + } + + // Avoid inlining the initialization closure into the common path that fetches + // the already initialized value + #[cold] + fn try_init(&self, f: F) -> Result<&T, E> + where + F: FnOnce() -> Result, + { + let val = f()?; // Note that *some* forms of reentrant initialization might lead to // UB (see `reentrant_init` test). I believe that just removing this // `panic`, while keeping `try_insert` would be sound, but it seems diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index b09d9fab8a763..0b22f3dc37441 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1128,7 +1128,7 @@ extern "rust-intrinsic" { /// any safety invariants. /// /// Consider using [`core::panic::Location::caller`] instead. - #[rustc_const_unstable(feature = "const_caller_location", issue = "76156")] + #[rustc_const_stable(feature = "const_caller_location", since = "CURRENT_RUSTC_VERSION")] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn caller_location() -> &'static crate::panic::Location<'static>; diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index ba19ca1f45d7c..2bc2c649a6de9 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -125,7 +125,6 @@ #![feature(const_array_into_iter_constructors)] #![feature(const_bigint_helper_methods)] #![feature(const_black_box)] -#![feature(const_caller_location)] #![feature(const_cell_into_inner)] #![feature(const_char_from_u32_unchecked)] #![feature(const_eval_select)] diff --git a/library/core/src/panic/location.rs b/library/core/src/panic/location.rs index 6dcf23dde87c7..4ad507d8b868b 100644 --- a/library/core/src/panic/location.rs +++ b/library/core/src/panic/location.rs @@ -81,7 +81,7 @@ impl<'a> Location<'a> { /// ``` #[must_use] #[stable(feature = "track_caller", since = "1.46.0")] - #[rustc_const_unstable(feature = "const_caller_location", issue = "76156")] + #[rustc_const_stable(feature = "const_caller_location", since = "CURRENT_RUSTC_VERSION")] #[track_caller] #[inline] pub const fn caller() -> &'static Location<'static> { @@ -123,7 +123,7 @@ impl<'a> Location<'a> { /// ``` #[must_use] #[stable(feature = "panic_hooks", since = "1.10.0")] - #[rustc_const_unstable(feature = "const_location_fields", issue = "102911")] + #[rustc_const_stable(feature = "const_location_fields", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn file(&self) -> &str { self.file @@ -148,7 +148,7 @@ impl<'a> Location<'a> { /// ``` #[must_use] #[stable(feature = "panic_hooks", since = "1.10.0")] - #[rustc_const_unstable(feature = "const_location_fields", issue = "102911")] + #[rustc_const_stable(feature = "const_location_fields", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn line(&self) -> u32 { self.line @@ -173,7 +173,7 @@ impl<'a> Location<'a> { /// ``` #[must_use] #[stable(feature = "panic_col", since = "1.25.0")] - #[rustc_const_unstable(feature = "const_location_fields", issue = "102911")] + #[rustc_const_stable(feature = "const_location_fields", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn column(&self) -> u32 { self.col diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 8c5e5ecf5fe9f..0c87860096f63 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -11,7 +11,6 @@ #![feature(const_align_offset)] #![feature(const_align_of_val_raw)] #![feature(const_black_box)] -#![feature(const_caller_location)] #![feature(const_cell_into_inner)] #![feature(const_hash)] #![feature(const_heap)] @@ -25,7 +24,6 @@ #![cfg_attr(not(bootstrap), feature(const_three_way_compare))] #![feature(const_trait_impl)] #![feature(const_likely)] -#![feature(const_location_fields)] #![feature(core_intrinsics)] #![feature(core_io_borrowed_buf)] #![feature(core_private_bignum)] diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs index 6d068613f8f30..fc830baccedd2 100644 --- a/library/std/src/sync/once_lock.rs +++ b/library/std/src/sync/once_lock.rs @@ -252,6 +252,46 @@ impl OnceLock { } } + /// Gets the mutable reference of the contents of the cell, initializing + /// it with `f` if the cell was empty. + /// + /// Many threads may call `get_mut_or_init` concurrently with different + /// initializing functions, but it is guaranteed that only one function + /// will be executed. + /// + /// # Panics + /// + /// If `f` panics, the panic is propagated to the caller, and the cell + /// remains uninitialized. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell_get_mut)] + /// + /// use std::sync::OnceLock; + /// + /// let mut cell = OnceLock::new(); + /// let value = cell.get_mut_or_init(|| 92); + /// assert_eq!(*value, 92); + /// + /// *value += 2; + /// assert_eq!(*value, 94); + /// + /// let value = cell.get_mut_or_init(|| unreachable!()); + /// assert_eq!(*value, 94); + /// ``` + #[inline] + #[unstable(feature = "once_cell_get_mut", issue = "121641")] + pub fn get_mut_or_init(&mut self, f: F) -> &mut T + where + F: FnOnce() -> T, + { + match self.get_mut_or_try_init(|| Ok::(f())) { + Ok(val) => val, + } + } + /// Gets the contents of the cell, initializing it with `f` if /// the cell was empty. If the cell was empty and `f` failed, an /// error is returned. @@ -303,6 +343,47 @@ impl OnceLock { Ok(unsafe { self.get_unchecked() }) } + /// Gets the mutable reference of the contents of the cell, initializing + /// it with `f` if the cell was empty. If the cell was empty and `f` failed, + /// an error is returned. + /// + /// # Panics + /// + /// If `f` panics, the panic is propagated to the caller, and + /// the cell remains uninitialized. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell_get_mut)] + /// + /// use std::sync::OnceLock; + /// + /// let mut cell: OnceLock = OnceLock::new(); + /// + /// // Failed initializers do not change the value + /// assert!(cell.get_mut_or_try_init(|| "not a number!".parse()).is_err()); + /// assert!(cell.get().is_none()); + /// + /// let value = cell.get_mut_or_try_init(|| "1234".parse()); + /// assert_eq!(value, Ok(&mut 1234)); + /// *value.unwrap() += 2; + /// assert_eq!(cell.get(), Some(&1236)) + /// ``` + #[inline] + #[unstable(feature = "once_cell_get_mut", issue = "121641")] + pub fn get_mut_or_try_init(&mut self, f: F) -> Result<&mut T, E> + where + F: FnOnce() -> Result, + { + if self.get().is_none() { + self.initialize(f)?; + } + debug_assert!(self.is_initialized()); + // SAFETY: The inner value has been initialized + Ok(unsafe { self.get_unchecked_mut() }) + } + /// Consumes the `OnceLock`, returning the wrapped value. Returns /// `None` if the cell was empty. /// diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index bacf5f0d33cec..028e0f6d05f4f 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -597,7 +597,7 @@ impl Step for Miri { builder.ensure(compile::Std::new(target_compiler, host)); let host_sysroot = builder.sysroot(target_compiler); - // # Run `cargo test`. + // Run `cargo test`. // This is with the Miri crate, so it uses the host compiler. let mut cargo = tool::prepare_tool_cargo( builder, @@ -652,15 +652,46 @@ impl Step for Miri { builder.run(&mut cargo); } } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct CargoMiri { + target: TargetSelection, +} + +impl Step for CargoMiri { + type Output = (); + const ONLY_HOSTS: bool = false; - // # Run `cargo miri test`. + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/miri/cargo-miri") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(CargoMiri { target: run.target }); + } + + /// Tests `cargo miri test`. + fn run(self, builder: &Builder<'_>) { + let host = builder.build.build; + let target = self.target; + let stage = builder.top_stage; + if stage == 0 { + eprintln!("cargo-miri cannot be tested at stage 0"); + std::process::exit(1); + } + + // This compiler runs on the host, we'll just use it for the target. + let compiler = builder.compiler(stage, host); + + // Run `cargo miri test`. // This is just a smoke test (Miri's own CI invokes this in a bunch of different ways and ensures // that we get the desired output), but that is sufficient to make sure that the libtest harness // itself executes properly under Miri, and that all the logic in `cargo-miri` does not explode. - // This is running the build `cargo-miri` for the given target, so we need the target compiler. let mut cargo = tool::prepare_tool_cargo( builder, - target_compiler, + compiler, Mode::ToolStd, // it's unclear what to use here, we're not building anything just doing a smoke test! target, "miri-test", diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 9555be481e695..e8977a4b173e7 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -808,6 +808,7 @@ impl<'a> Builder<'a> { test::EditionGuide, test::Rustfmt, test::Miri, + test::CargoMiri, test::Clippy, test::RustDemangler, test::CompiletestTest, diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh index 38c5b173ae31b..53b4583166d38 100755 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh @@ -32,9 +32,9 @@ python3 "$X_PY" test --stage 2 src/tools/rustfmt # that bugs which only surface when the GC runs at a specific time are more likely to cause CI to fail. # This significantly increases the runtime of our test suite, or we'd do this in PR CI too. if [ -z "${PR_CI_JOB:-}" ]; then - MIRIFLAGS=-Zmiri-provenance-gc=1 python3 "$X_PY" test --stage 2 src/tools/miri + MIRIFLAGS=-Zmiri-provenance-gc=1 python3 "$X_PY" test --stage 2 src/tools/miri src/tools/miri/cargo-miri else - python3 "$X_PY" test --stage 2 src/tools/miri + python3 "$X_PY" test --stage 2 src/tools/miri src/tools/miri/cargo-miri fi # We natively run this script on x86_64-unknown-linux-gnu and x86_64-pc-windows-msvc. # Also cover some other targets via cross-testing, in particular all tier 1 targets. @@ -42,8 +42,8 @@ case $HOST_TARGET in x86_64-unknown-linux-gnu) # Only this branch runs in PR CI. # Fully test all main OSes, including a 32bit target. - python3 "$X_PY" test --stage 2 src/tools/miri --target x86_64-apple-darwin - python3 "$X_PY" test --stage 2 src/tools/miri --target i686-pc-windows-msvc + python3 "$X_PY" test --stage 2 src/tools/miri src/tools/miri/cargo-miri --target x86_64-apple-darwin + python3 "$X_PY" test --stage 2 src/tools/miri src/tools/miri/cargo-miri --target i686-pc-windows-msvc # Only run "pass" tests for the remaining targets, which is quite a bit faster. python3 "$X_PY" test --stage 2 src/tools/miri --target x86_64-pc-windows-gnu --test-args pass python3 "$X_PY" test --stage 2 src/tools/miri --target i686-unknown-linux-gnu --test-args pass diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 80e2357440432..9323bb093ad96 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -249,7 +249,8 @@ x--expand-yaml-anchors--remove: <<: *step - name: run the build - run: src/ci/scripts/run-build-from-ci.sh + # Redirect stderr to stdout to avoid reordering the two streams in the GHA logs. + run: src/ci/scripts/run-build-from-ci.sh 2>&1 env: AWS_ACCESS_KEY_ID: ${{ env.CACHES_AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }} diff --git a/tests/ui/rfcs/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.rs b/tests/ui/rfcs/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.rs index 2ae8eb9c56d27..ef970ebd14bc2 100644 --- a/tests/ui/rfcs/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.rs +++ b/tests/ui/rfcs/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.rs @@ -6,7 +6,7 @@ //@ run-pass //@ compile-flags: -Z unleash-the-miri-inside-of-you -#![feature(core_intrinsics, const_caller_location)] +#![feature(core_intrinsics)] type L = &'static std::panic::Location<'static>; diff --git a/tests/ui/rfcs/rfc-2091-track-caller/const-caller-location.rs b/tests/ui/rfcs/rfc-2091-track-caller/const-caller-location.rs index 2c699437c8308..c4e1f3ae48a0b 100644 --- a/tests/ui/rfcs/rfc-2091-track-caller/const-caller-location.rs +++ b/tests/ui/rfcs/rfc-2091-track-caller/const-caller-location.rs @@ -2,15 +2,13 @@ //@ revisions: default mir-opt //@[mir-opt] compile-flags: -Zmir-opt-level=4 -#![feature(const_caller_location)] - use std::panic::Location; const LOCATION: &Location = Location::caller(); const TRACKED: &Location = tracked(); #[track_caller] -const fn tracked() -> &'static Location <'static> { +const fn tracked() -> &'static Location<'static> { Location::caller() } @@ -26,18 +24,18 @@ const fn contained() -> &'static Location<'static> { fn main() { assert_eq!(LOCATION.file(), file!()); - assert_eq!(LOCATION.line(), 9); + assert_eq!(LOCATION.line(), 7); assert_eq!(LOCATION.column(), 29); assert_eq!(TRACKED.file(), file!()); - assert_eq!(TRACKED.line(), 11); + assert_eq!(TRACKED.line(), 9); assert_eq!(TRACKED.column(), 28); assert_eq!(NESTED.file(), file!()); - assert_eq!(NESTED.line(), 19); + assert_eq!(NESTED.line(), 17); assert_eq!(NESTED.column(), 5); assert_eq!(CONTAINED.file(), file!()); - assert_eq!(CONTAINED.line(), 24); + assert_eq!(CONTAINED.line(), 22); assert_eq!(CONTAINED.column(), 5); }