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 {
|
||||
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 @@ where
|
|||
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 @@ 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
|
||||
/// non-copy and *might* have a destructor attached; if it returns
|
||||
/// `false`, then `ty` definitely has no destructor (i.e., no drop glue).
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue