Don't consider !Unpin references as noalias
Such structures may contain self-references, in which case the same location may be accessible through a pointer that is not based-on the noalias pointer. This is still grey area as far as language semantics are concerned, but checking for !Unpin as an indicator for self-referential sturctures seems like a good approach for the meantime.
This commit is contained in:
parent
08c5ffd4a3
commit
c3f9403f59
@ -993,6 +993,10 @@
|
||||
query is_freeze_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
|
||||
desc { "computing whether `{}` is freeze", env.value }
|
||||
}
|
||||
/// Query backing `TyS::is_unpin`.
|
||||
query is_unpin_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
|
||||
desc { "computing whether `{}` is `Unpin`", env.value }
|
||||
}
|
||||
/// Query backing `TyS::needs_drop`.
|
||||
query needs_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
|
||||
desc { "computing whether `{}` needs drop", env.value }
|
||||
|
@ -2318,16 +2318,25 @@ fn pointee_info_at(this: TyAndLayout<'tcx>, cx: &C, offset: Size) -> Option<Poin
|
||||
ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
|
||||
let address_space = addr_space_of_ty(ty);
|
||||
let tcx = cx.tcx();
|
||||
let is_freeze = ty.is_freeze(tcx.at(DUMMY_SP), cx.param_env());
|
||||
let kind = match mt {
|
||||
hir::Mutability::Not => {
|
||||
if is_freeze {
|
||||
if ty.is_freeze(tcx.at(DUMMY_SP), cx.param_env()) {
|
||||
PointerKind::Frozen
|
||||
} else {
|
||||
PointerKind::Shared
|
||||
}
|
||||
}
|
||||
hir::Mutability::Mut => PointerKind::UniqueBorrowed,
|
||||
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.at(DUMMY_SP), cx.param_env()) {
|
||||
PointerKind::UniqueBorrowed
|
||||
} else {
|
||||
PointerKind::Shared
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
cx.layout_of(ty).to_result().ok().map(|layout| PointeeInfo {
|
||||
|
@ -741,6 +741,46 @@ fn is_trivially_freeze(&self) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether values of this type `T` implement the `Unpin` trait.
|
||||
pub fn is_unpin(&'tcx self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
|
||||
self.is_trivially_unpin() || tcx_at.is_unpin_raw(param_env.and(self))
|
||||
}
|
||||
|
||||
/// Fast path helper for testing if a type is `Unpin`.
|
||||
///
|
||||
/// Returning true means the type is known to be `Unpin`. Returning
|
||||
/// `false` means nothing -- could be `Unpin`, might not be.
|
||||
fn is_trivially_unpin(&self) -> bool {
|
||||
match self.kind() {
|
||||
ty::Int(_)
|
||||
| ty::Uint(_)
|
||||
| ty::Float(_)
|
||||
| ty::Bool
|
||||
| ty::Char
|
||||
| ty::Str
|
||||
| ty::Never
|
||||
| ty::Ref(..)
|
||||
| ty::RawPtr(_)
|
||||
| ty::FnDef(..)
|
||||
| ty::Error(_)
|
||||
| ty::FnPtr(_) => true,
|
||||
ty::Tuple(_) => self.tuple_fields().all(Self::is_trivially_unpin),
|
||||
ty::Slice(elem_ty) | ty::Array(elem_ty, _) => elem_ty.is_trivially_unpin(),
|
||||
ty::Adt(..)
|
||||
| ty::Bound(..)
|
||||
| ty::Closure(..)
|
||||
| ty::Dynamic(..)
|
||||
| ty::Foreign(_)
|
||||
| ty::Generator(..)
|
||||
| ty::GeneratorWitness(_)
|
||||
| ty::Infer(_)
|
||||
| ty::Opaque(..)
|
||||
| ty::Param(_)
|
||||
| ty::Placeholder(_)
|
||||
| ty::Projection(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// If `ty.needs_drop(...)` returns `true`, then `ty` is definitely
|
||||
/// non-copy and *might* have a destructor attached; if it returns
|
||||
/// `false`, then `ty` definitely has no destructor (i.e., no drop glue).
|
||||
|
@ -18,6 +18,10 @@ fn is_freeze_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>
|
||||
is_item_raw(tcx, query, LangItem::Freeze)
|
||||
}
|
||||
|
||||
fn is_unpin_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
|
||||
is_item_raw(tcx, query, LangItem::Unpin)
|
||||
}
|
||||
|
||||
fn is_item_raw<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
|
||||
@ -37,5 +41,11 @@ fn is_item_raw<'tcx>(
|
||||
}
|
||||
|
||||
pub(crate) fn provide(providers: &mut ty::query::Providers) {
|
||||
*providers = ty::query::Providers { is_copy_raw, is_sized_raw, is_freeze_raw, ..*providers };
|
||||
*providers = ty::query::Providers {
|
||||
is_copy_raw,
|
||||
is_sized_raw,
|
||||
is_freeze_raw,
|
||||
is_unpin_raw,
|
||||
..*providers
|
||||
};
|
||||
}
|
||||
|
15
src/test/codegen/noalias-unpin.rs
Normal file
15
src/test/codegen/noalias-unpin.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// compile-flags: -Z mutable-noalias=yes
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
pub struct SelfRef {
|
||||
self_ref: *mut SelfRef,
|
||||
_pin: std::marker::PhantomPinned
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @test_self_ref(
|
||||
// CHECK-NOT: noalias
|
||||
#[no_mangle]
|
||||
pub unsafe fn test_self_ref(s: &mut SelfRef) {
|
||||
(*s.self_ref).self_ref = std::ptr::null_mut();
|
||||
}
|
Loading…
Reference in New Issue
Block a user