@@ -559,6 +559,7 @@ use crate::{
559559/// The `Option` type. See [the module level documentation](self) for more.
560560#[ derive( Copy , PartialOrd , Eq , Ord , Debug , Hash ) ]
561561#[ rustc_diagnostic_item = "Option" ]
562+ #[ cfg_attr( not( bootstrap) , lang = "Option" ) ]
562563#[ stable( feature = "rust1" , since = "1.0.0" ) ]
563564pub enum Option < T > {
564565 /// No value.
@@ -735,48 +736,6 @@ impl<T> Option<T> {
735736 }
736737 }
737738
738- /// This is a guess at how many bytes into the option the payload can be found.
739- ///
740- /// For niche-optimized types it's correct because it's pigeon-holed to only
741- /// one possible place. For other types, it's usually correct today, but
742- /// tweaks to the layout algorithm (particularly expansions of
743- /// `-Z randomize-layout`) might make it incorrect at any point.
744- ///
745- /// It's guaranteed to be a multiple of alignment (so will always give a
746- /// correctly-aligned location) and to be within the allocated object, so
747- /// is valid to use with `offset` and to use for a zero-sized read.
748- ///
749- /// FIXME: This is a horrible hack, but allows a nice optimization. It should
750- /// be replaced with `offset_of!` once that works on enum variants.
751- const SOME_BYTE_OFFSET_GUESS : isize = {
752- let some_uninit = Some ( mem:: MaybeUninit :: < T > :: uninit ( ) ) ;
753- let payload_ref = some_uninit. as_ref ( ) . unwrap ( ) ;
754- // SAFETY: `as_ref` gives an address inside the existing `Option`,
755- // so both pointers are derived from the same thing and the result
756- // cannot overflow an `isize`.
757- let offset = unsafe { <* const _ >:: byte_offset_from ( payload_ref, & some_uninit) } ;
758-
759- // The offset is into the object, so it's guaranteed to be non-negative.
760- assert ! ( offset >= 0 ) ;
761-
762- // The payload and the overall option are aligned,
763- // so the offset will be a multiple of the alignment too.
764- assert ! ( ( offset as usize ) % mem:: align_of:: <T >( ) == 0 ) ;
765-
766- let max_offset = mem:: size_of :: < Self > ( ) - mem:: size_of :: < T > ( ) ;
767- if offset as usize <= max_offset {
768- // There's enough space after this offset for a `T` to exist without
769- // overflowing the bounds of the object, so let's try it.
770- offset
771- } else {
772- // The offset guess is definitely wrong, so use the address
773- // of the original option since we have it already.
774- // This also correctly handles the case of layout-optimized enums
775- // where `max_offset == 0` and thus this is the only possibility.
776- 0
777- }
778- } ;
779-
780739 /// Returns a slice of the contained value, if any. If this is `None`, an
781740 /// empty slice is returned. This can be useful to have a single type of
782741 /// iterator over an `Option` or slice.
@@ -809,28 +768,29 @@ impl<T> Option<T> {
809768 #[ must_use]
810769 #[ unstable( feature = "option_as_slice" , issue = "108545" ) ]
811770 pub fn as_slice ( & self ) -> & [ T ] {
812- let payload_ptr: * const T =
813- // The goal here is that both arms here are calculating exactly
814- // the same pointer, and thus it'll be folded away when the guessed
815- // offset is correct, but if the guess is wrong for some reason
816- // it'll at least still be sound, just no longer optimal.
817- if let Some ( payload) = self {
818- payload
819- } else {
820- let self_ptr: * const Self = self ;
821- // SAFETY: `SOME_BYTE_OFFSET_GUESS` guarantees that its value is
822- // such that this will be in-bounds of the object.
823- unsafe { self_ptr. byte_offset ( Self :: SOME_BYTE_OFFSET_GUESS ) . cast ( ) }
824- } ;
825- let len = usize:: from ( self . is_some ( ) ) ;
771+ #[ cfg( bootstrap) ]
772+ match self {
773+ Some ( value) => slice:: from_ref ( value) ,
774+ None => & [ ] ,
775+ }
826776
777+ #[ cfg( not( bootstrap) ) ]
827778 // SAFETY: When the `Option` is `Some`, we're using the actual pointer
828779 // to the payload, with a length of 1, so this is equivalent to
829780 // `slice::from_ref`, and thus is safe.
830781 // When the `Option` is `None`, the length used is 0, so to be safe it
831782 // just needs to be aligned, which it is because `&self` is aligned and
832783 // the offset used is a multiple of alignment.
833- unsafe { slice:: from_raw_parts ( payload_ptr, len) }
784+ //
785+ // In the new version, the intrinsic always returns a pointer to an
786+ // in-bounds and correctly aligned position for a `T` (even if in the
787+ // `None` case it's just padding).
788+ unsafe {
789+ slice:: from_raw_parts (
790+ crate :: intrinsics:: option_payload_ptr ( crate :: ptr:: from_ref ( self ) ) ,
791+ usize:: from ( self . is_some ( ) ) ,
792+ )
793+ }
834794 }
835795
836796 /// Returns a mutable slice of the contained value, if any. If this is
@@ -875,28 +835,32 @@ impl<T> Option<T> {
875835 #[ must_use]
876836 #[ unstable( feature = "option_as_slice" , issue = "108545" ) ]
877837 pub fn as_mut_slice ( & mut self ) -> & mut [ T ] {
878- let payload_ptr: * mut T =
879- // The goal here is that both arms here are calculating exactly
880- // the same pointer, and thus it'll be folded away when the guessed
881- // offset is correct, but if the guess is wrong for some reason
882- // it'll at least still be sound, just no longer optimal.
883- if let Some ( payload) = self {
884- payload
885- } else {
886- let self_ptr: * mut Self = self ;
887- // SAFETY: `SOME_BYTE_OFFSET_GUESS` guarantees that its value is
888- // such that this will be in-bounds of the object.
889- unsafe { self_ptr. byte_offset ( Self :: SOME_BYTE_OFFSET_GUESS ) . cast ( ) }
890- } ;
891- let len = usize:: from ( self . is_some ( ) ) ;
838+ #[ cfg( bootstrap) ]
839+ match self {
840+ Some ( value) => slice:: from_mut ( value) ,
841+ None => & mut [ ] ,
842+ }
892843
844+ #[ cfg( not( bootstrap) ) ]
893845 // SAFETY: When the `Option` is `Some`, we're using the actual pointer
894846 // to the payload, with a length of 1, so this is equivalent to
895847 // `slice::from_mut`, and thus is safe.
896848 // When the `Option` is `None`, the length used is 0, so to be safe it
897849 // just needs to be aligned, which it is because `&self` is aligned and
898850 // the offset used is a multiple of alignment.
899- unsafe { slice:: from_raw_parts_mut ( payload_ptr, len) }
851+ //
852+ // In the new version, the intrinsic creates a `*const T` from a
853+ // mutable reference so it is safe to cast back to a mutable pointer
854+ // here. As with `as_slice`, the intrinsic always returns a pointer to
855+ // an in-bounds and correctly aligned position for a `T` (even if in
856+ // the `None` case it's just padding).
857+ unsafe {
858+ slice:: from_raw_parts_mut (
859+ crate :: intrinsics:: option_payload_ptr ( crate :: ptr:: from_mut ( self ) . cast_const ( ) )
860+ . cast_mut ( ) ,
861+ usize:: from ( self . is_some ( ) ) ,
862+ )
863+ }
900864 }
901865
902866 /////////////////////////////////////////////////////////////////////////
0 commit comments