@@ -1011,25 +1011,41 @@ where
10111011 }
10121012
10131013 _ => {
1014- let mut data_variant = match this. variants {
1014+ let mut data_variant = match & this. variants {
10151015 // Within the discriminant field, only the niche itself is
10161016 // always initialized, so we only check for a pointer at its
10171017 // offset.
10181018 //
1019- // If the niche is a pointer, it's either valid (according
1020- // to its type), or null (which the niche field's scalar
1021- // validity range encodes). This allows using
1022- // `dereferenceable_or_null` for e.g., `Option<&T>`, and
1023- // this will continue to work as long as we don't start
1024- // using more niches than just null (e.g., the first page of
1025- // the address space, or unaligned pointers).
1019+ // Our goal here is to check whether this represents a
1020+ // "dereferenceable or null" pointer, so we need to ensure
1021+ // that there is only one other variant, and it must be null.
1022+ // Below, we will then check whether the pointer is indeed
1023+ // dereferenceable.
10261024 Variants :: Multiple {
1027- tag_encoding : TagEncoding :: Niche { untagged_variant, .. } ,
1025+ tag_encoding :
1026+ TagEncoding :: Niche { untagged_variant, niche_variants, niche_start } ,
10281027 tag_field,
1028+ variants,
10291029 ..
1030- } if this. fields . offset ( tag_field) == offset => {
1031- Some ( this. for_variant ( cx, untagged_variant) )
1030+ } if variants. len ( ) == 2 && this. fields . offset ( * tag_field) == offset => {
1031+ let tagged_variant = if untagged_variant. as_u32 ( ) == 0 {
1032+ VariantIdx :: from_u32 ( 1 )
1033+ } else {
1034+ VariantIdx :: from_u32 ( 0 )
1035+ } ;
1036+ assert_eq ! ( tagged_variant, * niche_variants. start( ) ) ;
1037+ if * niche_start == 0 {
1038+ // The other variant is encoded as "null", so we can recurse searching for
1039+ // a pointer here. This relies on the fact that the codegen backend
1040+ // only adds "dereferenceable" if there's also a "nonnull" proof,
1041+ // and that null is aligned for all alignments so it's okay to forward
1042+ // the pointer's alignment.
1043+ Some ( this. for_variant ( cx, * untagged_variant) )
1044+ } else {
1045+ None
1046+ }
10321047 }
1048+ Variants :: Multiple { .. } => None ,
10331049 _ => Some ( this) ,
10341050 } ;
10351051
0 commit comments