Auto merge of #60237 - saleemjaffer:issue-56166-miri-fntype-arg-passing, r=eddyb

Move pointee_info_at from rustc_codegen_llvm to rustc_target.

Makes progress towards #56166.

This is a continuation of https://github.com/rust-lang/rust/pull/57150.

@oli-obk Should I close the older PR?
This commit is contained in:
bors 2019-05-05 18:25:13 +00:00
commit d628c2e642
10 changed files with 233 additions and 154 deletions

View file

@ -12,6 +12,7 @@ use std::iter;
use std::mem;
use std::ops::Bound;
use crate::hir;
use crate::ich::StableHashingContext;
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
@ -1518,6 +1519,10 @@ pub trait HasTyCtxt<'tcx>: HasDataLayout {
fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx>;
}
pub trait HasParamEnv<'tcx> {
fn param_env(&self) -> ty::ParamEnv<'tcx>;
}
impl<'a, 'gcx, 'tcx> HasDataLayout for TyCtxt<'a, 'gcx, 'tcx> {
fn data_layout(&self) -> &TargetDataLayout {
&self.data_layout
@ -1530,6 +1535,12 @@ impl<'a, 'gcx, 'tcx> HasTyCtxt<'gcx> for TyCtxt<'a, 'gcx, 'tcx> {
}
}
impl<'tcx, C> HasParamEnv<'tcx> for LayoutCx<'tcx, C> {
fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.param_env
}
}
impl<'tcx, T: HasDataLayout> HasDataLayout for LayoutCx<'tcx, T> {
fn data_layout(&self) -> &TargetDataLayout {
self.tcx.data_layout()
@ -1543,25 +1554,32 @@ impl<'gcx, 'tcx, T: HasTyCtxt<'gcx>> HasTyCtxt<'gcx> for LayoutCx<'tcx, T> {
}
pub trait MaybeResult<T> {
fn from_ok(x: T) -> Self;
fn map_same<F: FnOnce(T) -> T>(self, f: F) -> Self;
type Error;
fn from(x: Result<T, Self::Error>) -> Self;
fn to_result(self) -> Result<T, Self::Error>;
}
impl<T> MaybeResult<T> for T {
fn from_ok(x: T) -> Self {
type Error = !;
fn from(x: Result<T, Self::Error>) -> Self {
let Ok(x) = x;
x
}
fn map_same<F: FnOnce(T) -> T>(self, f: F) -> Self {
f(self)
fn to_result(self) -> Result<T, Self::Error> {
Ok(self)
}
}
impl<T, E> MaybeResult<T> for Result<T, E> {
fn from_ok(x: T) -> Self {
Ok(x)
type Error = E;
fn from(x: Result<T, Self::Error>) -> Self {
x
}
fn map_same<F: FnOnce(T) -> T>(self, f: F) -> Self {
self.map(f)
fn to_result(self) -> Result<T, Self::Error> {
self
}
}
@ -1656,7 +1674,8 @@ impl ty::query::TyCtxtAt<'a, 'tcx, '_> {
impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx>
where C: LayoutOf<Ty = Ty<'tcx>> + HasTyCtxt<'tcx>,
C::TyLayout: MaybeResult<TyLayout<'tcx>>
C::TyLayout: MaybeResult<TyLayout<'tcx>>,
C: HasParamEnv<'tcx>
{
fn for_variant(this: TyLayout<'tcx>, cx: &C, variant_index: VariantIdx) -> TyLayout<'tcx> {
let details = match this.variants {
@ -1664,10 +1683,9 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx>
Variants::Single { index } => {
// Deny calling for_variant more than once for non-Single enums.
cx.layout_of(this.ty).map_same(|layout| {
if let Ok(layout) = cx.layout_of(this.ty).to_result() {
assert_eq!(layout.variants, Variants::Single { index });
layout
});
}
let fields = match this.ty.sty {
ty::Adt(def, _) => def.variants[variant_index].fields.len(),
@ -1700,10 +1718,10 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx>
let tcx = cx.tcx();
let discr_layout = |discr: &Scalar| -> C::TyLayout {
let layout = LayoutDetails::scalar(cx, discr.clone());
MaybeResult::from_ok(TyLayout {
MaybeResult::from(Ok(TyLayout {
details: tcx.intern_layout(layout),
ty: discr.value.to_ty(tcx)
})
ty: discr.value.to_ty(tcx),
}))
};
cx.layout_of(match this.ty.sty {
@ -1737,10 +1755,10 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx>
} else {
tcx.mk_mut_ref(tcx.lifetimes.re_static, nil)
};
return cx.layout_of(ptr_ty).map_same(|mut ptr_layout| {
return MaybeResult::from(cx.layout_of(ptr_ty).to_result().map(|mut ptr_layout| {
ptr_layout.ty = this.ty;
ptr_layout
});
}));
}
match tcx.struct_tail(pointee).sty {
@ -1824,6 +1842,130 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx>
}
})
}
fn pointee_info_at(
this: TyLayout<'tcx>,
cx: &C,
offset: Size,
) -> Option<PointeeInfo> {
match this.ty.sty {
ty::RawPtr(mt) if offset.bytes() == 0 => {
cx.layout_of(mt.ty).to_result().ok()
.map(|layout| PointeeInfo {
size: layout.size,
align: layout.align.abi,
safe: None,
})
}
ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
let tcx = cx.tcx();
let is_freeze = ty.is_freeze(tcx, cx.param_env(), DUMMY_SP);
let kind = match mt {
hir::MutImmutable => if is_freeze {
PointerKind::Frozen
} else {
PointerKind::Shared
},
hir::MutMutable => {
// Previously we would only emit noalias annotations for LLVM >= 6 or in
// panic=abort mode. That was deemed right, as prior versions had many bugs
// in conjunction with unwinding, but later versions didnt seem to have
// said issues. See issue #31681.
//
// Alas, later on we encountered a case where noalias would generate wrong
// code altogether even with recent versions of LLVM in *safe* code with no
// unwinding involved. See #54462.
//
// For now, do not enable mutable_noalias by default at all, while the
// issue is being figured out.
let mutable_noalias = tcx.sess.opts.debugging_opts.mutable_noalias
.unwrap_or(false);
if mutable_noalias {
PointerKind::UniqueBorrowed
} else {
PointerKind::Shared
}
}
};
cx.layout_of(ty).to_result().ok()
.map(|layout| PointeeInfo {
size: layout.size,
align: layout.align.abi,
safe: Some(kind),
})
}
_ => {
let mut data_variant = match this.variants {
// Within the discriminant field, only the niche itself is
// always initialized, so we only check for a pointer at its
// offset.
//
// If the niche is a pointer, it's either valid (according
// to its type), or null (which the niche field's scalar
// validity range encodes). This allows using
// `dereferenceable_or_null` for e.g., `Option<&T>`, and
// this will continue to work as long as we don't start
// using more niches than just null (e.g., the first page of
// the address space, or unaligned pointers).
Variants::Multiple {
discr_kind: DiscriminantKind::Niche {
dataful_variant,
..
},
discr_index,
..
} if this.fields.offset(discr_index) == offset =>
Some(this.for_variant(cx, dataful_variant)),
_ => Some(this),
};
if let Some(variant) = data_variant {
// We're not interested in any unions.
if let FieldPlacement::Union(_) = variant.fields {
data_variant = None;
}
}
let mut result = None;
if let Some(variant) = data_variant {
let ptr_end = offset + Pointer.size(cx);
for i in 0..variant.fields.count() {
let field_start = variant.fields.offset(i);
if field_start <= offset {
let field = variant.field(cx, i);
result = field.to_result().ok()
.and_then(|field| {
if ptr_end <= field_start + field.size {
// We found the right field, look inside it.
field.pointee_info_at(cx, offset - field_start)
} else {
None
}
});
if result.is_some() {
break;
}
}
}
}
// FIXME(eddyb) This should be for `ptr::Unique<T>`, not `Box<T>`.
if let Some(ref mut pointee) = result {
if let ty::Adt(def, _) = this.ty.sty {
if def.is_box() && offset.bytes() == 0 {
pointee.safe = Some(PointerKind::UniqueOwned);
}
}
}
result
}
}
}
}
struct Niche {