@@ -1036,6 +1036,9 @@ where
10361036 this : TyAndLayout < ' tcx > ,
10371037 cx : & C ,
10381038 offset : Size ,
1039+ // If true, assume that pointers are either null or valid (according to their type),
1040+ // enabling extra optimizations.
1041+ mut assume_valid_ptr : bool ,
10391042 ) -> Option < PointeeInfo > {
10401043 let tcx = cx. tcx ( ) ;
10411044 let param_env = cx. param_env ( ) ;
@@ -1058,19 +1061,19 @@ where
10581061 // Freeze/Unpin queries, and can save time in the codegen backend (noalias
10591062 // attributes in LLVM have compile-time cost even in unoptimized builds).
10601063 let optimize = tcx. sess . opts . optimize != OptLevel :: No ;
1061- let kind = match mt {
1062- hir:: Mutability :: Not => PointerKind :: SharedRef {
1064+ let safe = match ( assume_valid_ptr , mt ) {
1065+ ( true , hir:: Mutability :: Not ) => Some ( PointerKind :: SharedRef {
10631066 frozen : optimize && ty. is_freeze ( tcx, cx. param_env ( ) ) ,
1064- } ,
1065- hir:: Mutability :: Mut => PointerKind :: MutableRef {
1067+ } ) ,
1068+ ( true , hir:: Mutability :: Mut ) => Some ( PointerKind :: MutableRef {
10661069 unpin : optimize && ty. is_unpin ( tcx, cx. param_env ( ) ) ,
1067- } ,
1070+ } ) ,
1071+ ( false , _) => None ,
10681072 } ;
1069-
10701073 tcx. layout_of ( param_env. and ( ty) ) . ok ( ) . map ( |layout| PointeeInfo {
10711074 size : layout. size ,
10721075 align : layout. align . abi ,
1073- safe : Some ( kind ) ,
1076+ safe,
10741077 } )
10751078 }
10761079
@@ -1079,20 +1082,21 @@ where
10791082 // Within the discriminant field, only the niche itself is
10801083 // always initialized, so we only check for a pointer at its
10811084 // offset.
1082- //
1083- // If the niche is a pointer, it's either valid (according
1084- // to its type), or null (which the niche field's scalar
1085- // validity range encodes). This allows using
1086- // `dereferenceable_or_null` for e.g., `Option<&T>`, and
1087- // this will continue to work as long as we don't start
1088- // using more niches than just null (e.g., the first page of
1089- // the address space, or unaligned pointers).
1090- // FIXME(reference_niches): well, the day has come...
10911085 Variants :: Multiple {
1092- tag_encoding : TagEncoding :: Niche { untagged_variant, .. } ,
1086+ tag_encoding :
1087+ TagEncoding :: Niche {
1088+ untagged_variant,
1089+ niche_variants : ref variants,
1090+ niche_start,
1091+ } ,
10931092 tag_field,
10941093 ..
10951094 } if this. fields . offset ( tag_field) == offset => {
1095+ // We can only continue assuming pointer validity if the only possible
1096+ // discriminant value is null. The null special-case is permitted by LLVM's
1097+ // `dereferenceable_or_null`, and allow types like `Option<&T>` to benefit
1098+ // from optimizations.
1099+ assume_valid_ptr &= niche_start == 0 && variants. start ( ) == variants. end ( ) ;
10961100 Some ( this. for_variant ( cx, untagged_variant) )
10971101 }
10981102 _ => Some ( this) ,
@@ -1118,9 +1122,12 @@ where
11181122 result = field. to_result ( ) . ok ( ) . and_then ( |field| {
11191123 if ptr_end <= field_start + field. size {
11201124 // We found the right field, look inside it.
1121- let field_info =
1122- field. pointee_info_at ( cx, offset - field_start) ;
1123- field_info
1125+ Self :: ty_and_layout_pointee_info_at (
1126+ field,
1127+ cx,
1128+ offset - field_start,
1129+ assume_valid_ptr,
1130+ )
11241131 } else {
11251132 None
11261133 }
@@ -1135,7 +1142,7 @@ where
11351142 // FIXME(eddyb) This should be for `ptr::Unique<T>`, not `Box<T>`.
11361143 if let Some ( ref mut pointee) = result {
11371144 if let ty:: Adt ( def, _) = this. ty . kind ( ) {
1138- if def. is_box ( ) && offset. bytes ( ) == 0 {
1145+ if assume_valid_ptr && def. is_box ( ) && offset. bytes ( ) == 0 {
11391146 let optimize = tcx. sess . opts . optimize != OptLevel :: No ;
11401147 pointee. safe = Some ( PointerKind :: Box {
11411148 unpin : optimize && this. ty . boxed_ty ( ) . is_unpin ( tcx, cx. param_env ( ) ) ,
0 commit comments