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 {

View File

@ -2,8 +2,8 @@ use crate::llvm::{self, AttributePlace};
use crate::builder::Builder;
use crate::context::CodegenCx;
use crate::type_::Type;
use crate::type_of::{LayoutLlvmExt, PointerKind};
use crate::value::Value;
use crate::type_of::{LayoutLlvmExt};
use rustc_codegen_ssa::MemFlags;
use rustc_codegen_ssa::mir::place::PlaceRef;
use rustc_codegen_ssa::mir::operand::OperandValue;
@ -13,7 +13,7 @@ use rustc_codegen_ssa::traits::*;
use rustc_target::abi::{HasDataLayout, LayoutOf, Size, TyLayout, Abi as LayoutAbi};
use rustc::ty::{self, Ty, Instance};
use rustc::ty::layout;
use rustc::ty::layout::{self, PointerKind};
use libc::c_uint;

View File

@ -66,6 +66,12 @@ impl ty::layout::HasTyCtxt<'tcx> for Builder<'_, '_, 'tcx> {
}
}
impl ty::layout::HasParamEnv<'tcx> for Builder<'_, '_, 'tcx> {
fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.cx.param_env()
}
}
impl ty::layout::LayoutOf for Builder<'_, '_, 'tcx> {
type Ty = Ty<'tcx>;
type TyLayout = TyLayout<'tcx>;

View File

@ -8,7 +8,6 @@ use rustc::hir;
use crate::monomorphize::partitioning::CodegenUnit;
use crate::type_::Type;
use crate::type_of::PointeeInfo;
use rustc_codegen_ssa::traits::*;
use rustc_data_structures::base_n;
@ -16,7 +15,9 @@ use rustc_data_structures::small_c_str::SmallCStr;
use rustc::mir::mono::Stats;
use rustc::session::config::{self, DebugInfo};
use rustc::session::Session;
use rustc::ty::layout::{LayoutError, LayoutOf, Size, TyLayout, VariantIdx};
use rustc::ty::layout::{
LayoutError, LayoutOf, PointeeInfo, Size, TyLayout, VariantIdx, HasParamEnv
};
use rustc::ty::{self, Ty, TyCtxt};
use rustc::util::nodemap::FxHashMap;
use rustc_target::spec::{HasTargetSpec, Target};
@ -862,3 +863,9 @@ impl LayoutOf for CodegenCx<'ll, 'tcx> {
})
}
}
impl<'tcx, 'll> HasParamEnv<'tcx> for CodegenCx<'ll, 'tcx> {
fn param_env(&self) -> ty::ParamEnv<'tcx> {
ty::ParamEnv::reveal_all()
}
}

View File

@ -1,10 +1,9 @@
use crate::abi::{FnType, FnTypeExt};
use crate::common::*;
use crate::type_::Type;
use rustc::hir;
use rustc::ty::{self, Ty, TypeFoldable};
use rustc::ty::layout::{self, Align, LayoutOf, Size, TyLayout};
use rustc_target::abi::FloatTy;
use rustc::ty::layout::{self, Align, LayoutOf, PointeeInfo, Size, TyLayout};
use rustc_target::abi::{FloatTy, TyLayoutMethods};
use rustc_mir::monomorphize::item::DefPathBasedNames;
use rustc_codegen_ssa::traits::*;
@ -174,28 +173,6 @@ impl<'a, 'tcx> CodegenCx<'a, 'tcx> {
}
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum PointerKind {
/// Most general case, we know no restrictions to tell LLVM.
Shared,
/// `&T` where `T` contains no `UnsafeCell`, is `noalias` and `readonly`.
Frozen,
/// `&mut T`, when we know `noalias` is safe for LLVM.
UniqueBorrowed,
/// `Box<T>`, unlike `UniqueBorrowed`, it also has `noalias` on returns.
UniqueOwned
}
#[derive(Copy, Clone)]
pub struct PointeeInfo {
pub size: Size,
pub align: Align,
pub safe: Option<PointerKind>,
}
pub trait LayoutLlvmExt<'tcx> {
fn is_llvm_immediate(&self) -> bool;
fn is_llvm_scalar_pair<'a>(&self) -> bool;
@ -406,112 +383,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
return pointee;
}
let mut result = None;
match self.ty.sty {
ty::RawPtr(mt) if offset.bytes() == 0 => {
let (size, align) = cx.size_and_align_of(mt.ty);
result = Some(PointeeInfo {
size,
align,
safe: None
});
}
ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
let (size, align) = cx.size_and_align_of(ty);
let kind = match mt {
hir::MutImmutable => if cx.type_is_freeze(ty) {
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 = cx.tcx.sess.opts.debugging_opts.mutable_noalias
.unwrap_or(false);
if mutable_noalias {
PointerKind::UniqueBorrowed
} else {
PointerKind::Shared
}
}
};
result = Some(PointeeInfo {
size,
align,
safe: Some(kind)
});
}
_ => {
let mut data_variant = match self.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).
layout::Variants::Multiple {
discr_kind: layout::DiscriminantKind::Niche {
dataful_variant,
..
},
discr_index,
..
} if self.fields.offset(discr_index) == offset =>
Some(self.for_variant(cx, dataful_variant)),
_ => Some(*self),
};
if let Some(variant) = data_variant {
// We're not interested in any unions.
if let layout::FieldPlacement::Union(_) = variant.fields {
data_variant = None;
}
}
if let Some(variant) = data_variant {
let ptr_end = offset + layout::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);
if ptr_end <= field_start + field.size {
// We found the right field, look inside it.
result = field.pointee_info_at(cx, offset - field_start);
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, _) = self.ty.sty {
if def.is_box() && offset.bytes() == 0 {
pointee.safe = Some(PointerKind::UniqueOwned);
}
}
}
}
}
let result = Ty::pointee_info_at(*self, cx, offset);
cx.pointee_infos.borrow_mut().insert((self.ty, offset), result);
result

View File

@ -10,7 +10,7 @@ use crate::mir::operand::OperandRef;
use crate::mir::place::PlaceRef;
use crate::MemFlags;
use rustc::ty::Ty;
use rustc::ty::layout::{Align, Size};
use rustc::ty::layout::{Align, Size, HasParamEnv};
use std::ops::Range;
use std::iter::TrustedLen;
@ -29,6 +29,8 @@ pub trait BuilderMethods<'a, 'tcx: 'a>:
+ IntrinsicCallMethods<'tcx>
+ AsmBuilderMethods<'tcx>
+ StaticBuilderMethods<'tcx>
+ HasParamEnv<'tcx>
{
fn new_block<'b>(cx: &'a Self::CodegenCx, llfn: Self::Value, name: &'b str) -> Self;
fn with_cx(cx: &'a Self::CodegenCx) -> Self;

View File

@ -41,6 +41,8 @@ pub use self::type_::{
ArgTypeMethods, BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods, TypeMethods,
};
pub use self::write::{ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods};
use rustc::ty::layout::{HasParamEnv};
use std::fmt;
@ -58,6 +60,7 @@ pub trait CodegenMethods<'tcx>:
+ DeclareMethods<'tcx>
+ AsmMethods<'tcx>
+ PreDefineMethods<'tcx>
+ HasParamEnv<'tcx>
{
}
@ -72,6 +75,7 @@ impl<'tcx, T> CodegenMethods<'tcx> for T where
+ DeclareMethods<'tcx>
+ AsmMethods<'tcx>
+ PreDefineMethods<'tcx>
+ HasParamEnv<'tcx>
{
}

View File

@ -175,6 +175,14 @@ impl<'a, 'mir, 'tcx, M> layout::HasTyCtxt<'tcx> for InterpretCx<'a, 'mir, 'tcx,
}
}
impl<'a, 'mir, 'tcx, M> layout::HasParamEnv<'tcx> for InterpretCx<'a, 'mir, 'tcx, M>
where M: Machine<'a, 'mir, 'tcx>
{
fn param_env(&self) -> ty::ParamEnv<'tcx> {
self.param_env
}
}
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> LayoutOf
for InterpretCx<'a, 'mir, 'tcx, M>
{

View File

@ -7,6 +7,7 @@ use rustc::ty::layout::HasTyCtxt;
use rustc::ty::layout::LayoutOf;
use rustc::ty::layout::TargetDataLayout;
use rustc::ty::layout::TyLayout;
use rustc::ty::layout::HasParamEnv;
use rustc::ty::ParamEnv;
use rustc::ty::Ty;
use rustc::ty::TyCtxt;
@ -122,6 +123,12 @@ impl<'me, 'tcx> HasTyCtxt<'tcx> for UnwrapLayoutCx<'me, 'tcx> {
}
}
impl<'me, 'tcx> HasParamEnv<'tcx> for UnwrapLayoutCx<'me, 'tcx> {
fn param_env(&self) -> ParamEnv<'tcx> {
self.param_env
}
}
impl<'me, 'tcx> HasDataLayout for UnwrapLayoutCx<'me, 'tcx> {
fn data_layout(&self) -> &TargetDataLayout {
self.tcx.data_layout()

View File

@ -910,6 +910,28 @@ pub trait LayoutOf {
fn layout_of(&self, ty: Self::Ty) -> Self::TyLayout;
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum PointerKind {
/// Most general case, we know no restrictions to tell LLVM.
Shared,
/// `&T` where `T` contains no `UnsafeCell`, is `noalias` and `readonly`.
Frozen,
/// `&mut T`, when we know `noalias` is safe for LLVM.
UniqueBorrowed,
/// `Box<T>`, unlike `UniqueBorrowed`, it also has `noalias` on returns.
UniqueOwned
}
#[derive(Copy, Clone)]
pub struct PointeeInfo {
pub size: Size,
pub align: Align,
pub safe: Option<PointerKind>,
}
pub trait TyLayoutMethods<'a, C: LayoutOf<Ty = Self>>: Sized {
fn for_variant(
this: TyLayout<'a, Self>,
@ -917,6 +939,11 @@ pub trait TyLayoutMethods<'a, C: LayoutOf<Ty = Self>>: Sized {
variant_index: VariantIdx,
) -> TyLayout<'a, Self>;
fn field(this: TyLayout<'a, Self>, cx: &C, i: usize) -> C::TyLayout;
fn pointee_info_at(
this: TyLayout<'a, Self>,
cx: &C,
offset: Size,
) -> Option<PointeeInfo>;
}
impl<'a, Ty> TyLayout<'a, Ty> {
@ -928,6 +955,10 @@ impl<'a, Ty> TyLayout<'a, Ty> {
where Ty: TyLayoutMethods<'a, C>, C: LayoutOf<Ty = Ty> {
Ty::field(self, cx, i)
}
pub fn pointee_info_at<C>(self, cx: &C, offset: Size) -> Option<PointeeInfo>
where Ty: TyLayoutMethods<'a, C>, C: LayoutOf<Ty = Ty> {
Ty::pointee_info_at(self, cx, offset)
}
}
impl<'a, Ty> TyLayout<'a, Ty> {