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
5 changed files with 82 additions and 4 deletions
|
@ -993,6 +993,10 @@ rustc_queries! {
|
||||||
query is_freeze_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
|
query is_freeze_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
|
||||||
desc { "computing whether `{}` is freeze", env.value }
|
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 backing `TyS::needs_drop`.
|
||||||
query needs_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
|
query needs_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
|
||||||
desc { "computing whether `{}` needs drop", env.value }
|
desc { "computing whether `{}` needs drop", env.value }
|
||||||
|
|
|
@ -2318,16 +2318,25 @@ where
|
||||||
ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
|
ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
|
||||||
let address_space = addr_space_of_ty(ty);
|
let address_space = addr_space_of_ty(ty);
|
||||||
let tcx = cx.tcx();
|
let tcx = cx.tcx();
|
||||||
let is_freeze = ty.is_freeze(tcx.at(DUMMY_SP), cx.param_env());
|
|
||||||
let kind = match mt {
|
let kind = match mt {
|
||||||
hir::Mutability::Not => {
|
hir::Mutability::Not => {
|
||||||
if is_freeze {
|
if ty.is_freeze(tcx.at(DUMMY_SP), cx.param_env()) {
|
||||||
PointerKind::Frozen
|
PointerKind::Frozen
|
||||||
} else {
|
} else {
|
||||||
PointerKind::Shared
|
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 {
|
cx.layout_of(ty).to_result().ok().map(|layout| PointeeInfo {
|
||||||
|
|
|
@ -741,6 +741,46 @@ impl<'tcx> ty::TyS<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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
|
/// If `ty.needs_drop(...)` returns `true`, then `ty` is definitely
|
||||||
/// non-copy and *might* have a destructor attached; if it returns
|
/// non-copy and *might* have a destructor attached; if it returns
|
||||||
/// `false`, then `ty` definitely has no destructor (i.e., no drop glue).
|
/// `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)
|
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>(
|
fn is_item_raw<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
query: ty::ParamEnvAnd<'tcx, Ty<'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) {
|
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…
Add table
Add a link
Reference in a new issue