Skip to content

Commit 7157cfe

Browse files
committed
Implement unwrap_unchecked using transmutes when niche-optimizations are in play
1 parent 89e4e1f commit 7157cfe

File tree

3 files changed

+29
-1
lines changed

3 files changed

+29
-1
lines changed

library/core/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@
188188
#![feature(extern_types)]
189189
#![feature(fundamental)]
190190
#![feature(if_let_guard)]
191+
#![feature(inline_const)]
191192
#![feature(intra_doc_pointers)]
192193
#![feature(intrinsics)]
193194
#![feature(lang_items)]

library/core/src/option.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,11 +504,13 @@
504504

505505
use crate::iter::{self, FromIterator, FusedIterator, TrustedLen};
506506
use crate::marker::Destruct;
507+
use crate::mem::ManuallyDrop;
507508
use crate::panicking::{panic, panic_str};
508509
use crate::pin::Pin;
509510
use crate::{
510511
convert, hint, mem,
511512
ops::{self, ControlFlow, Deref, DerefMut},
513+
ptr,
512514
};
513515

514516
/// The `Option` type. See [the module level documentation](self) for more.
@@ -891,6 +893,14 @@ impl<T> Option<T> {
891893
#[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
892894
pub const unsafe fn unwrap_unchecked(self) -> T {
893895
debug_assert!(self.is_some());
896+
// Make things easier for the optimizer when niches are involved
897+
if const { mem::size_of::<T>() == mem::size_of::<Self>() } {
898+
// SAFETY: Size equality implies niches are involved. And with niches
899+
// transmutes are ok because they don't change bits, only make use of invalid values
900+
unsafe {
901+
return ptr::read(&ManuallyDrop::new(self) as *const _ as *const T);
902+
}
903+
}
894904
match self {
895905
Some(val) => val,
896906
// SAFETY: the safety contract must be upheld by the caller.

library/core/src/result.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,8 +491,9 @@
491491

492492
use crate::iter::{self, FromIterator, FusedIterator, TrustedLen};
493493
use crate::marker::Destruct;
494+
use crate::mem::ManuallyDrop;
494495
use crate::ops::{self, ControlFlow, Deref, DerefMut};
495-
use crate::{convert, fmt, hint};
496+
use crate::{convert, fmt, hint, mem, ptr};
496497

497498
/// `Result` is a type that represents either success ([`Ok`]) or failure ([`Err`]).
498499
///
@@ -1524,6 +1525,14 @@ impl<T, E> Result<T, E> {
15241525
#[stable(feature = "option_result_unwrap_unchecked", since = "1.58.0")]
15251526
pub unsafe fn unwrap_unchecked(self) -> T {
15261527
debug_assert!(self.is_ok());
1528+
// Make things easier for the optimizer when niches are involved
1529+
if const { mem::size_of::<T>() == mem::size_of::<Self>() } {
1530+
// SAFETY: Size equality implies niches are involved. And with niches
1531+
// transmutes are ok because they don't change bits, only make use of invalid values
1532+
unsafe {
1533+
return ptr::read(&ManuallyDrop::new(self) as *const _ as *const T);
1534+
}
1535+
}
15271536
match self {
15281537
Ok(t) => t,
15291538
// SAFETY: the safety contract must be upheld by the caller.
@@ -1556,6 +1565,14 @@ impl<T, E> Result<T, E> {
15561565
#[stable(feature = "option_result_unwrap_unchecked", since = "1.58.0")]
15571566
pub unsafe fn unwrap_err_unchecked(self) -> E {
15581567
debug_assert!(self.is_err());
1568+
// Make things easier for the optimizer when niches are involved
1569+
if const { mem::size_of::<E>() == mem::size_of::<Self>() } {
1570+
// SAFETY: Size equality implies niches are involved. And with niches
1571+
// transmutes are ok because they don't change bits, only make use of invalid values
1572+
unsafe {
1573+
return ptr::read(&ManuallyDrop::new(self) as *const _ as *const E);
1574+
}
1575+
}
15591576
match self {
15601577
// SAFETY: the safety contract must be upheld by the caller.
15611578
Ok(_) => unsafe { hint::unreachable_unchecked() },

0 commit comments

Comments
 (0)