make PointerKind directly reflect pointer types
The code that consumes PointerKind (`adjust_for_rust_scalar` in rustc_ty_utils) ended up using PointerKind variants to talk about Rust reference types (& and &mut) anyway, making the old code structure quite confusing: one always had to keep in mind which PointerKind corresponds to which type. So this changes PointerKind to directly reflect the type. This does not change behavior.
This commit is contained in:
parent
0c13c17250
commit
201ae73872
4 changed files with 40 additions and 59 deletions
|
@ -1439,21 +1439,12 @@ impl<V: Idx> fmt::Debug for LayoutS<V> {
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
pub enum PointerKind {
|
pub enum PointerKind {
|
||||||
/// Most general case, we know no restrictions to tell LLVM.
|
/// Shared reference. `frozen` indicates the absence of any `UnsafeCell`.
|
||||||
SharedMutable,
|
SharedRef { frozen: bool },
|
||||||
|
/// Mutable reference. `unpin` indicates the absence of any pinned data.
|
||||||
/// `&T` where `T` contains no `UnsafeCell`, is `dereferenceable`, `noalias` and `readonly`.
|
MutableRef { unpin: bool },
|
||||||
Frozen,
|
/// Box.
|
||||||
|
Box,
|
||||||
/// `&mut T` which is `dereferenceable` and `noalias` but not `readonly`.
|
|
||||||
UniqueBorrowed,
|
|
||||||
|
|
||||||
/// `&mut !Unpin`, which is `dereferenceable` but neither `noalias` nor `readonly`.
|
|
||||||
UniqueBorrowedPinned,
|
|
||||||
|
|
||||||
/// `Box<T>`, which is `noalias` (even on return types, unlike the above) but neither `readonly`
|
|
||||||
/// nor `dereferenceable`.
|
|
||||||
UniqueOwned,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Note that this information is advisory only, and backends are free to ignore it.
|
/// Note that this information is advisory only, and backends are free to ignore it.
|
||||||
|
|
|
@ -833,32 +833,17 @@ where
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
|
ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
|
||||||
let kind = if tcx.sess.opts.optimize == OptLevel::No {
|
// Use conservative pointer kind if not optimizing. This saves us the
|
||||||
// Use conservative pointer kind if not optimizing. This saves us the
|
// Freeze/Unpin queries, and can save time in the codegen backend (noalias
|
||||||
// Freeze/Unpin queries, and can save time in the codegen backend (noalias
|
// attributes in LLVM have compile-time cost even in unoptimized builds).
|
||||||
// attributes in LLVM have compile-time cost even in unoptimized builds).
|
let optimize = tcx.sess.opts.optimize != OptLevel::No;
|
||||||
PointerKind::SharedMutable
|
let kind = match mt {
|
||||||
} else {
|
hir::Mutability::Not => PointerKind::SharedRef {
|
||||||
match mt {
|
frozen: optimize && ty.is_freeze(tcx, cx.param_env()),
|
||||||
hir::Mutability::Not => {
|
},
|
||||||
if ty.is_freeze(tcx, cx.param_env()) {
|
hir::Mutability::Mut => PointerKind::MutableRef {
|
||||||
PointerKind::Frozen
|
unpin: optimize && ty.is_unpin(tcx, cx.param_env()),
|
||||||
} else {
|
},
|
||||||
PointerKind::SharedMutable
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hir::Mutability::Mut => {
|
|
||||||
// References to self-referential structures should not be considered
|
|
||||||
// noalias, as another pointer to the structure can be obtained, that
|
|
||||||
// is not based-on the original reference. We consider all !Unpin
|
|
||||||
// types to be potentially self-referential here.
|
|
||||||
if ty.is_unpin(tcx, cx.param_env()) {
|
|
||||||
PointerKind::UniqueBorrowed
|
|
||||||
} else {
|
|
||||||
PointerKind::UniqueBorrowedPinned
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
tcx.layout_of(param_env.and(ty)).ok().map(|layout| PointeeInfo {
|
tcx.layout_of(param_env.and(ty)).ok().map(|layout| PointeeInfo {
|
||||||
|
@ -929,7 +914,7 @@ where
|
||||||
if let Some(ref mut pointee) = result {
|
if let Some(ref mut pointee) = result {
|
||||||
if let ty::Adt(def, _) = this.ty.kind() {
|
if let ty::Adt(def, _) = this.ty.kind() {
|
||||||
if def.is_box() && offset.bytes() == 0 {
|
if def.is_box() && offset.bytes() == 0 {
|
||||||
pointee.safe = Some(PointerKind::UniqueOwned);
|
pointee.safe = Some(PointerKind::Box);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -254,15 +254,15 @@ fn adjust_for_rust_scalar<'tcx>(
|
||||||
if let Some(kind) = pointee.safe {
|
if let Some(kind) = pointee.safe {
|
||||||
attrs.pointee_align = Some(pointee.align);
|
attrs.pointee_align = Some(pointee.align);
|
||||||
|
|
||||||
// `Box` (`UniqueBorrowed`) are not necessarily dereferenceable
|
// `Box` are not necessarily dereferenceable for the entire duration of the function as
|
||||||
// for the entire duration of the function as they can be deallocated
|
// they can be deallocated at any time. Same for non-frozen shared references (see
|
||||||
// at any time. Same for shared mutable references. If LLVM had a
|
// <https://github.com/rust-lang/rust/pull/98017>). If LLVM had a way to say
|
||||||
// way to say "dereferenceable on entry" we could use it here.
|
// "dereferenceable on entry" we could use it here.
|
||||||
attrs.pointee_size = match kind {
|
attrs.pointee_size = match kind {
|
||||||
PointerKind::UniqueBorrowed
|
PointerKind::Box | PointerKind::SharedRef { frozen: false } => Size::ZERO,
|
||||||
| PointerKind::UniqueBorrowedPinned
|
PointerKind::SharedRef { frozen: true } | PointerKind::MutableRef { .. } => {
|
||||||
| PointerKind::Frozen => pointee.size,
|
pointee.size
|
||||||
PointerKind::SharedMutable | PointerKind::UniqueOwned => Size::ZERO,
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// The aliasing rules for `Box<T>` are still not decided, but currently we emit
|
// The aliasing rules for `Box<T>` are still not decided, but currently we emit
|
||||||
|
@ -278,15 +278,14 @@ fn adjust_for_rust_scalar<'tcx>(
|
||||||
// `&mut` pointer parameters never alias other parameters,
|
// `&mut` pointer parameters never alias other parameters,
|
||||||
// or mutable global data
|
// or mutable global data
|
||||||
//
|
//
|
||||||
// `&T` where `T` contains no `UnsafeCell<U>` is immutable,
|
// `&T` where `T` contains no `UnsafeCell<U>` is immutable, and can be marked as both
|
||||||
// and can be marked as both `readonly` and `noalias`, as
|
// `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely on memory
|
||||||
// LLVM's definition of `noalias` is based solely on memory
|
// dependencies rather than pointer equality. However this only applies to arguments,
|
||||||
// dependencies rather than pointer equality
|
// not return values.
|
||||||
let no_alias = match kind {
|
let no_alias = match kind {
|
||||||
PointerKind::SharedMutable | PointerKind::UniqueBorrowedPinned => false,
|
PointerKind::SharedRef { frozen } => frozen,
|
||||||
PointerKind::UniqueBorrowed => noalias_mut_ref,
|
PointerKind::MutableRef { unpin } => unpin && noalias_mut_ref,
|
||||||
PointerKind::UniqueOwned => noalias_for_box,
|
PointerKind::Box => noalias_for_box,
|
||||||
PointerKind::Frozen => true,
|
|
||||||
};
|
};
|
||||||
// We can never add `noalias` in return position; that LLVM attribute has some very surprising semantics
|
// We can never add `noalias` in return position; that LLVM attribute has some very surprising semantics
|
||||||
// (see <https://github.com/rust-lang/unsafe-code-guidelines/issues/385#issuecomment-1368055745>).
|
// (see <https://github.com/rust-lang/unsafe-code-guidelines/issues/385#issuecomment-1368055745>).
|
||||||
|
@ -294,7 +293,7 @@ fn adjust_for_rust_scalar<'tcx>(
|
||||||
attrs.set(ArgAttribute::NoAlias);
|
attrs.set(ArgAttribute::NoAlias);
|
||||||
}
|
}
|
||||||
|
|
||||||
if kind == PointerKind::Frozen && !is_return {
|
if matches!(kind, PointerKind::SharedRef { frozen: true }) && !is_return {
|
||||||
attrs.set(ArgAttribute::ReadOnly);
|
attrs.set(ArgAttribute::ReadOnly);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,12 @@ pub fn borrow(x: &i32) -> &i32 {
|
||||||
x
|
x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CHECK: align 4 {{i32\*|ptr}} @borrow_mut({{i32\*|ptr}} align 4 %x)
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn borrow_mut(x: &mut i32) -> &mut i32 {
|
||||||
|
x
|
||||||
|
}
|
||||||
|
|
||||||
// CHECK-LABEL: @borrow_call
|
// CHECK-LABEL: @borrow_call
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn borrow_call(x: &i32, f: fn(&i32) -> &i32) -> &i32 {
|
pub fn borrow_call(x: &i32, f: fn(&i32) -> &i32) -> &i32 {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue