@@ -559,6 +559,7 @@ use crate::{
559
559
/// The `Option` type. See [the module level documentation](self) for more.
560
560
#[ derive( Copy , PartialOrd , Eq , Ord , Debug , Hash ) ]
561
561
#[ rustc_diagnostic_item = "Option" ]
562
+ #[ cfg_attr( not( bootstrap) , lang = "Option" ) ]
562
563
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
563
564
pub enum Option < T > {
564
565
/// No value.
@@ -735,48 +736,6 @@ impl<T> Option<T> {
735
736
}
736
737
}
737
738
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
-
780
739
/// Returns a slice of the contained value, if any. If this is `None`, an
781
740
/// empty slice is returned. This can be useful to have a single type of
782
741
/// iterator over an `Option` or slice.
@@ -809,28 +768,29 @@ impl<T> Option<T> {
809
768
#[ must_use]
810
769
#[ unstable( feature = "option_as_slice" , issue = "108545" ) ]
811
770
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
+ }
826
776
777
+ #[ cfg( not( bootstrap) ) ]
827
778
// SAFETY: When the `Option` is `Some`, we're using the actual pointer
828
779
// to the payload, with a length of 1, so this is equivalent to
829
780
// `slice::from_ref`, and thus is safe.
830
781
// When the `Option` is `None`, the length used is 0, so to be safe it
831
782
// just needs to be aligned, which it is because `&self` is aligned and
832
783
// 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
+ }
834
794
}
835
795
836
796
/// Returns a mutable slice of the contained value, if any. If this is
@@ -875,28 +835,32 @@ impl<T> Option<T> {
875
835
#[ must_use]
876
836
#[ unstable( feature = "option_as_slice" , issue = "108545" ) ]
877
837
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
+ }
892
843
844
+ #[ cfg( not( bootstrap) ) ]
893
845
// SAFETY: When the `Option` is `Some`, we're using the actual pointer
894
846
// to the payload, with a length of 1, so this is equivalent to
895
847
// `slice::from_mut`, and thus is safe.
896
848
// When the `Option` is `None`, the length used is 0, so to be safe it
897
849
// just needs to be aligned, which it is because `&self` is aligned and
898
850
// 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
+ }
900
864
}
901
865
902
866
/////////////////////////////////////////////////////////////////////////
0 commit comments