about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-10-14 22:56:33 +0000
committerbors <bors@rust-lang.org>2023-10-14 22:56:33 +0000
commite292fec36880f48101bda4054be37097312e73c0 (patch)
tree3f56ee0bb5fe64873e7763eefb90174ebefdecd4
parentc543b6f3516767150af84d94c14a27b19d4b0291 (diff)
parent31b86ea6fc189e4146a6f02ab872a5d2b18358e3 (diff)
downloadrust-e292fec36880f48101bda4054be37097312e73c0.tar.gz
rust-e292fec36880f48101bda4054be37097312e73c0.zip
Auto merge of #116742 - GuillaumeGomez:rollup-xjxs0mr, r=GuillaumeGomez
Rollup of 3 pull requests

Successful merges:

 - #116540 (Implement `OnceCell/Lock::try_insert()`)
 - #116576 (const-eval: allow calling functions with targat features disabled at compile time in WASM)
 - #116661 (Make "request changes" reviews apply `S-waiting-on-author`)

Failed merges:

 - #116643 (x.py zsh completion support)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_const_eval/src/interpret/terminator.rs10
-rw-r--r--library/core/src/cell/once.rs46
-rw-r--r--library/std/src/sync/once_lock.rs43
-rwxr-xr-xsrc/tools/miri/ci.sh4
-rw-r--r--src/tools/miri/tests/pass/function_calls/target_feature_wasm.rs11
-rw-r--r--tests/ui/consts/const-eval/const_fn_target_feature_wasm.rs14
-rw-r--r--triagebot.toml6
7 files changed, 116 insertions, 18 deletions
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index 578dd6622aa..9750b0df2f5 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -890,11 +890,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     }
 
     fn check_fn_target_features(&self, instance: ty::Instance<'tcx>) -> InterpResult<'tcx, ()> {
+        // Calling functions with `#[target_feature]` is not unsafe on WASM, see #84988
         let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
-        if attrs
-            .target_features
-            .iter()
-            .any(|feature| !self.tcx.sess.target_features.contains(feature))
+        if !self.tcx.sess.target.is_like_wasm
+            && attrs
+                .target_features
+                .iter()
+                .any(|feature| !self.tcx.sess.target_features.contains(feature))
         {
             throw_ub_custom!(
                 fluent::const_eval_unavailable_target_features_for_fn,
diff --git a/library/core/src/cell/once.rs b/library/core/src/cell/once.rs
index 2e8534f651a..3877a0c48cb 100644
--- a/library/core/src/cell/once.rs
+++ b/library/core/src/cell/once.rs
@@ -87,10 +87,40 @@ impl<T> OnceCell<T> {
     #[inline]
     #[stable(feature = "once_cell", since = "1.70.0")]
     pub fn set(&self, value: T) -> Result<(), T> {
-        // SAFETY: Safe because we cannot have overlapping mutable borrows
-        let slot = unsafe { &*self.inner.get() };
-        if slot.is_some() {
-            return Err(value);
+        match self.try_insert(value) {
+            Ok(_) => Ok(()),
+            Err((_, value)) => Err(value),
+        }
+    }
+
+    /// Sets the contents of the cell to `value` if the cell was empty, then
+    /// returns a reference to it.
+    ///
+    /// # Errors
+    ///
+    /// This method returns `Ok(&value)` if the cell was empty and
+    /// `Err(&current_value, value)` if it was full.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell_try_insert)]
+    ///
+    /// use std::cell::OnceCell;
+    ///
+    /// let cell = OnceCell::new();
+    /// assert!(cell.get().is_none());
+    ///
+    /// assert_eq!(cell.try_insert(92), Ok(&92));
+    /// assert_eq!(cell.try_insert(62), Err((&92, 62)));
+    ///
+    /// assert!(cell.get().is_some());
+    /// ```
+    #[inline]
+    #[unstable(feature = "once_cell_try_insert", issue = "116693")]
+    pub fn try_insert(&self, value: T) -> Result<&T, (&T, T)> {
+        if let Some(old) = self.get() {
+            return Err((old, value));
         }
 
         // SAFETY: This is the only place where we set the slot, no races
@@ -98,8 +128,7 @@ impl<T> OnceCell<T> {
         // checked that slot is currently `None`, so this write
         // maintains the `inner`'s invariant.
         let slot = unsafe { &mut *self.inner.get() };
-        *slot = Some(value);
-        Ok(())
+        Ok(slot.insert(value))
     }
 
     /// Gets the contents of the cell, initializing it with `f`
@@ -183,10 +212,9 @@ impl<T> OnceCell<T> {
         let val = outlined_call(f)?;
         // Note that *some* forms of reentrant initialization might lead to
         // UB (see `reentrant_init` test). I believe that just removing this
-        // `assert`, while keeping `set/get` would be sound, but it seems
+        // `panic`, while keeping `try_insert` would be sound, but it seems
         // better to panic, rather than to silently use an old value.
-        assert!(self.set(val).is_ok(), "reentrant init");
-        Ok(self.get().unwrap())
+        if let Ok(val) = self.try_insert(val) { Ok(val) } else { panic!("reentrant init") }
     }
 
     /// Consumes the cell, returning the wrapped value.
diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs
index e2b7b893cb5..f4963090795 100644
--- a/library/std/src/sync/once_lock.rs
+++ b/library/std/src/sync/once_lock.rs
@@ -126,11 +126,48 @@ impl<T> OnceLock<T> {
     #[inline]
     #[stable(feature = "once_cell", since = "1.70.0")]
     pub fn set(&self, value: T) -> Result<(), T> {
+        match self.try_insert(value) {
+            Ok(_) => Ok(()),
+            Err((_, value)) => Err(value),
+        }
+    }
+
+    /// Sets the contents of this cell to `value` if the cell was empty, then
+    /// returns a reference to it.
+    ///
+    /// May block if another thread is currently attempting to initialize the cell. The cell is
+    /// guaranteed to contain a value when set returns, though not necessarily the one provided.
+    ///
+    /// Returns `Ok(&value)` if the cell was empty and `Err(&current_value, value)` if it was full.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(once_cell_try_insert)]
+    ///
+    /// use std::sync::OnceLock;
+    ///
+    /// static CELL: OnceLock<i32> = OnceLock::new();
+    ///
+    /// fn main() {
+    ///     assert!(CELL.get().is_none());
+    ///
+    ///     std::thread::spawn(|| {
+    ///         assert_eq!(CELL.try_insert(92), Ok(&92));
+    ///     }).join().unwrap();
+    ///
+    ///     assert_eq!(CELL.try_insert(62), Err((&92, 62)));
+    ///     assert_eq!(CELL.get(), Some(&92));
+    /// }
+    /// ```
+    #[inline]
+    #[unstable(feature = "once_cell_try_insert", issue = "116693")]
+    pub fn try_insert(&self, value: T) -> Result<&T, (&T, T)> {
         let mut value = Some(value);
-        self.get_or_init(|| value.take().unwrap());
+        let res = self.get_or_init(|| value.take().unwrap());
         match value {
-            None => Ok(()),
-            Some(value) => Err(value),
+            None => Ok(res),
+            Some(value) => Err((res, value)),
         }
     }
 
diff --git a/src/tools/miri/ci.sh b/src/tools/miri/ci.sh
index 1b3ed796c66..eda1ceb4084 100755
--- a/src/tools/miri/ci.sh
+++ b/src/tools/miri/ci.sh
@@ -110,8 +110,8 @@ case $HOST_TARGET in
     MIRI_TEST_TARGET=i686-pc-windows-gnu run_tests
     MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple atomic data_race env/var
     MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal hello integer vec panic/panic
-    MIRI_TEST_TARGET=wasm32-wasi run_tests_minimal no_std integer strings
-    MIRI_TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std integer strings
+    MIRI_TEST_TARGET=wasm32-wasi run_tests_minimal no_std integer strings wasm
+    MIRI_TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std integer strings wasm
     MIRI_TEST_TARGET=thumbv7em-none-eabihf run_tests_minimal no_std # no_std embedded architecture
     MIRI_TEST_TARGET=tests/avr.json MIRI_NO_STD=1 run_tests_minimal no_std # JSON target file
     ;;
diff --git a/src/tools/miri/tests/pass/function_calls/target_feature_wasm.rs b/src/tools/miri/tests/pass/function_calls/target_feature_wasm.rs
new file mode 100644
index 00000000000..5056f32de44
--- /dev/null
+++ b/src/tools/miri/tests/pass/function_calls/target_feature_wasm.rs
@@ -0,0 +1,11 @@
+//@only-target-wasm32: tests WASM-specific behavior
+//@compile-flags: -C target-feature=-simd128
+
+fn main() {
+    // Calling functions with `#[target_feature]` is not unsound on WASM, see #84988
+    assert!(!cfg!(target_feature = "simd128"));
+    simd128_fn();
+}
+
+#[target_feature(enable = "simd128")]
+fn simd128_fn() {}
diff --git a/tests/ui/consts/const-eval/const_fn_target_feature_wasm.rs b/tests/ui/consts/const-eval/const_fn_target_feature_wasm.rs
new file mode 100644
index 00000000000..c1460fdd9ec
--- /dev/null
+++ b/tests/ui/consts/const-eval/const_fn_target_feature_wasm.rs
@@ -0,0 +1,14 @@
+// only-wasm32
+// compile-flags:-C target-feature=-simd128
+// build-pass
+
+#![crate_type = "lib"]
+
+#[cfg(target_feature = "simd128")]
+compile_error!("simd128 target feature should be disabled");
+
+// Calling functions with `#[target_feature]` is not unsound on WASM, see #84988
+const A: () = simd128_fn();
+
+#[target_feature(enable = "simd128")]
+const fn simd128_fn() {}
diff --git a/triagebot.toml b/triagebot.toml
index 4b051db0d73..9e23fd71c4a 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -23,6 +23,12 @@ allow-unauthenticated = [
     "needs-triage",
 ]
 
+[review-submitted] 
+# This label is added when a "request changes" review is submitted. 
+reviewed_label = "S-waiting-on-author" 
+# These labels are removed when a "request changes" review is submitted. 
+review_labels = ["S-waiting-on-review"]
+
 [glacier]
 
 [ping.icebreakers-llvm]