about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAurelia Molzer <5550310+HeroicKatora@users.noreply.github.com>2025-08-09 21:40:12 +0200
committerAurelia Molzer <5550310+197g@users.noreply.github.com>2025-08-09 21:44:31 +0200
commit7d7fe3ff05c7c14834252e3345389e4dbf842cc5 (patch)
tree3f68270936b0dd0c48c019beeaf56f1e33e25a75
parent21bdfa14cbd99aba173751a2c723fb1e65de401b (diff)
Adjust for codegen of unpredictable return value
It seems important for LLVM that we select on the values by-value
instead of reading and have no intermediate store. So make sure the
guards selects both potential drops but defers the return value to the
second selection. Since the two options alias we use raw mutable
pointers instead of mutable references as before.
-rw-r--r--library/core/src/hint.rs36
1 files changed, 31 insertions, 5 deletions
diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs
index 53c17d6c887..1bb1c569508 100644
--- a/library/core/src/hint.rs
+++ b/library/core/src/hint.rs
@@ -786,16 +786,42 @@ pub fn select_unpredictable<T>(condition: bool, true_val: T, false_val: T) -> T
     // Change this to use ManuallyDrop instead.
     let mut true_val = MaybeUninit::new(true_val);
     let mut false_val = MaybeUninit::new(false_val);
+
+    struct DropOnPanic<T> {
+        inner: *mut MaybeUninit<T>,
+    }
+
+    impl<T> Drop for DropOnPanic<T> {
+        fn drop(&mut self) {
+            // SAFETY: Must be guaranteed on construction of local type `DropOnPanic`.
+            unsafe { (*self.inner).assume_init_drop() }
+        }
+    }
+
+    let true_ptr = (&mut true_val) as *mut _;
+    let false_ptr = (&mut false_val) as *mut _;
+
     // SAFETY: The value that is not selected is dropped, and the selected one
     // is returned. This is necessary because the intrinsic doesn't drop the
     // value that is  not selected.
     unsafe {
         // Extract the selected value first, ensure it is dropped as well if dropping the unselected
         // value panics.
-        let ret = crate::intrinsics::select_unpredictable(condition, &true_val, &false_val)
-            .assume_init_read();
-        crate::intrinsics::select_unpredictable(!condition, &mut true_val, &mut false_val)
-            .assume_init_drop();
-        ret
+        let (guard, drop) = crate::intrinsics::select_unpredictable(
+            condition,
+            (true_ptr, false_ptr),
+            (false_ptr, true_ptr),
+        );
+
+        // SAFETY: both pointers are to valid `MaybeUninit`, in both variants they do not alias but
+        // the two arguments we have selected from did alias each other.
+        let guard = DropOnPanic { inner: guard };
+        (*drop).assume_init_drop();
+        crate::mem::forget(guard);
+
+        // Note that it is important to use the values here. Reading from the pointer we got makes
+        // LLVM forget the !unpredictable annotation sometimes (in tests, integer sized values in
+        // particular seemed to confuse it, also observed in llvm/llvm-project #82340).
+        crate::intrinsics::select_unpredictable(condition, true_val, false_val).assume_init()
     }
 }