From 7157cfec956a4af4d89a2ba5562d1deebdd8101e Mon Sep 17 00:00:00 2001 From: The 8472 Date: Thu, 22 Sep 2022 21:41:24 +0200 Subject: [PATCH] Implement unwrap_unchecked using transmutes when niche-optimizations are in play --- library/core/src/lib.rs | 1 + library/core/src/option.rs | 10 ++++++++++ library/core/src/result.rs | 19 ++++++++++++++++++- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 21775c0a6ab0b..a0e647c6b50c0 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -188,6 +188,7 @@ #![feature(extern_types)] #![feature(fundamental)] #![feature(if_let_guard)] +#![feature(inline_const)] #![feature(intra_doc_pointers)] #![feature(intrinsics)] #![feature(lang_items)] diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 934175863630f..0f210523e93e4 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -504,11 +504,13 @@ use crate::iter::{self, FromIterator, FusedIterator, TrustedLen}; use crate::marker::Destruct; +use crate::mem::ManuallyDrop; use crate::panicking::{panic, panic_str}; use crate::pin::Pin; use crate::{ convert, hint, mem, ops::{self, ControlFlow, Deref, DerefMut}, + ptr, }; /// The `Option` type. See [the module level documentation](self) for more. @@ -891,6 +893,14 @@ impl Option { #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")] pub const unsafe fn unwrap_unchecked(self) -> T { debug_assert!(self.is_some()); + // Make things easier for the optimizer when niches are involved + if const { mem::size_of::() == mem::size_of::() } { + // SAFETY: Size equality implies niches are involved. And with niches + // transmutes are ok because they don't change bits, only make use of invalid values + unsafe { + return ptr::read(&ManuallyDrop::new(self) as *const _ as *const T); + } + } match self { Some(val) => val, // SAFETY: the safety contract must be upheld by the caller. diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 76eaa191f7811..cc1f39a1e6646 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -491,8 +491,9 @@ use crate::iter::{self, FromIterator, FusedIterator, TrustedLen}; use crate::marker::Destruct; +use crate::mem::ManuallyDrop; use crate::ops::{self, ControlFlow, Deref, DerefMut}; -use crate::{convert, fmt, hint}; +use crate::{convert, fmt, hint, mem, ptr}; /// `Result` is a type that represents either success ([`Ok`]) or failure ([`Err`]). /// @@ -1524,6 +1525,14 @@ impl Result { #[stable(feature = "option_result_unwrap_unchecked", since = "1.58.0")] pub unsafe fn unwrap_unchecked(self) -> T { debug_assert!(self.is_ok()); + // Make things easier for the optimizer when niches are involved + if const { mem::size_of::() == mem::size_of::() } { + // SAFETY: Size equality implies niches are involved. And with niches + // transmutes are ok because they don't change bits, only make use of invalid values + unsafe { + return ptr::read(&ManuallyDrop::new(self) as *const _ as *const T); + } + } match self { Ok(t) => t, // SAFETY: the safety contract must be upheld by the caller. @@ -1556,6 +1565,14 @@ impl Result { #[stable(feature = "option_result_unwrap_unchecked", since = "1.58.0")] pub unsafe fn unwrap_err_unchecked(self) -> E { debug_assert!(self.is_err()); + // Make things easier for the optimizer when niches are involved + if const { mem::size_of::() == mem::size_of::() } { + // SAFETY: Size equality implies niches are involved. And with niches + // transmutes are ok because they don't change bits, only make use of invalid values + unsafe { + return ptr::read(&ManuallyDrop::new(self) as *const _ as *const E); + } + } match self { // SAFETY: the safety contract must be upheld by the caller. Ok(_) => unsafe { hint::unreachable_unchecked() },