@@ -736,46 +736,15 @@ impl<T> Option<T> {
736736 }
737737
738738 /// 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- } ;
739+ /// As this version will only be ever used to compile rustc and the performance
740+ /// penalty is negligible, use a minimal implementation here.
741+ #[ cfg( bootstrap) ]
742+ const SOME_BYTE_OFFSET_GUESS : usize = 0 ;
743+
744+ // FIXME: replace this with whatever stable method to get the offset of an enum
745+ // field may appear first.
746+ #[ cfg( not( bootstrap) ) ]
747+ const SOME_BYTE_OFFSET_GUESS : usize = crate :: intrinsics:: option_some_offset :: < Option < T > > ( ) ;
779748
780749 /// Returns a slice of the contained value, if any. If this is `None`, an
781750 /// empty slice is returned. This can be useful to have a single type of
@@ -820,7 +789,7 @@ impl<T> Option<T> {
820789 let self_ptr: * const Self = self ;
821790 // SAFETY: `SOME_BYTE_OFFSET_GUESS` guarantees that its value is
822791 // such that this will be in-bounds of the object.
823- unsafe { self_ptr. byte_offset ( Self :: SOME_BYTE_OFFSET_GUESS ) . cast ( ) }
792+ unsafe { self_ptr. byte_add ( Self :: SOME_BYTE_OFFSET_GUESS ) . cast ( ) }
824793 } ;
825794 let len = usize:: from ( self . is_some ( ) ) ;
826795
@@ -886,7 +855,7 @@ impl<T> Option<T> {
886855 let self_ptr: * mut Self = self ;
887856 // SAFETY: `SOME_BYTE_OFFSET_GUESS` guarantees that its value is
888857 // such that this will be in-bounds of the object.
889- unsafe { self_ptr. byte_offset ( Self :: SOME_BYTE_OFFSET_GUESS ) . cast ( ) }
858+ unsafe { self_ptr. byte_add ( Self :: SOME_BYTE_OFFSET_GUESS ) . cast ( ) }
890859 } ;
891860 let len = usize:: from ( self . is_some ( ) ) ;
892861
0 commit comments