Skip to content

Commit 403f34b

Browse files
committed
Don't treat ref. fields with non-null niches as dereferenceable_or_null
1 parent 4fb039e commit 403f34b

File tree

4 files changed

+37
-25
lines changed

4 files changed

+37
-25
lines changed

compiler/rustc_codegen_gcc/src/type_of.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,8 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
339339
return pointee;
340340
}
341341

342-
let result = Ty::ty_and_layout_pointee_info_at(*self, cx, offset);
342+
let assume_valid_ptr = true;
343+
let result = Ty::ty_and_layout_pointee_info_at(*self, cx, offset, assume_valid_ptr);
343344

344345
cx.pointee_infos.borrow_mut().insert((self.ty, offset), result);
345346
result

compiler/rustc_codegen_llvm/src/type_of.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -411,8 +411,8 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
411411
if let Some(&pointee) = cx.pointee_infos.borrow().get(&(self.ty, offset)) {
412412
return pointee;
413413
}
414-
415-
let result = Ty::ty_and_layout_pointee_info_at(*self, cx, offset);
414+
let assume_valid_ptr = true;
415+
let result = Ty::ty_and_layout_pointee_info_at(*self, cx, offset, assume_valid_ptr);
416416

417417
cx.pointee_infos.borrow_mut().insert((self.ty, offset), result);
418418
result

compiler/rustc_middle/src/ty/layout.rs

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -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()),

compiler/rustc_target/src/abi/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ pub trait TyAbiInterface<'a, C>: Sized {
5050
this: TyAndLayout<'a, Self>,
5151
cx: &C,
5252
offset: Size,
53+
// If true, assume that pointers are either null or valid (according to their type),
54+
// enabling extra optimizations.
55+
assume_valid_ptr: bool,
5356
) -> Option<PointeeInfo>;
5457
fn is_adt(this: TyAndLayout<'a, Self>) -> bool;
5558
fn is_never(this: TyAndLayout<'a, Self>) -> bool;
@@ -76,7 +79,8 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
7679
where
7780
Ty: TyAbiInterface<'a, C>,
7881
{
79-
Ty::ty_and_layout_pointee_info_at(self, cx, offset)
82+
let assume_valid_ptr = true;
83+
Ty::ty_and_layout_pointee_info_at(self, cx, offset, assume_valid_ptr)
8084
}
8185

8286
pub fn is_single_fp_element<C>(self, cx: &C) -> bool

0 commit comments

Comments
 (0)