diff options
| author | Aurelia Molzer <5550310+HeroicKatora@users.noreply.github.com> | 2025-08-09 21:40:12 +0200 |
|---|---|---|
| committer | Aurelia Molzer <5550310+197g@users.noreply.github.com> | 2025-08-09 21:44:31 +0200 |
| commit | 7d7fe3ff05c7c14834252e3345389e4dbf842cc5 (patch) | |
| tree | 3f68270936b0dd0c48c019beeaf56f1e33e25a75 | |
| parent | 21bdfa14cbd99aba173751a2c723fb1e65de401b (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.rs | 36 |
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() } } |
