Skip to content

Commit

Permalink
Rollup merge of rust-lang#58301 - RalfJung:fat-ptr-eq, r=oli-obk
Browse files Browse the repository at this point in the history
Enable comparing fat pointers

Also refactor our binops a bit to make that happen more easily.

r? @oli-obk
  • Loading branch information
Centril committed Feb 14, 2019
2 parents 56e1916 + 22d5e6a commit fab0f9b
Show file tree
Hide file tree
Showing 11 changed files with 146 additions and 130 deletions.
26 changes: 8 additions & 18 deletions src/librustc_mir/const_eval.rs
Expand Up @@ -11,7 +11,7 @@ use rustc::hir::def::Def;
use rustc::mir::interpret::{ConstEvalErr, ErrorHandled};
use rustc::mir;
use rustc::ty::{self, TyCtxt, query::TyCtxtAt};
use rustc::ty::layout::{self, LayoutOf, TyLayout, VariantIdx};
use rustc::ty::layout::{self, LayoutOf, VariantIdx};
use rustc::ty::subst::Subst;
use rustc::traits::Reveal;
use rustc_data_structures::fx::FxHashMap;
Expand All @@ -21,7 +21,8 @@ use syntax::ast::Mutability;
use syntax::source_map::{Span, DUMMY_SP};

use crate::interpret::{self,
PlaceTy, MPlaceTy, MemPlace, OpTy, Operand, Immediate, Scalar, RawConst, ConstValue, Pointer,
PlaceTy, MPlaceTy, MemPlace, OpTy, ImmTy, Operand, Immediate, Scalar, Pointer,
RawConst, ConstValue,
EvalResult, EvalError, EvalErrorKind, GlobalId, EvalContext, StackPopCleanup,
Allocation, AllocId, MemoryKind,
snapshot, RefTracking,
Expand Down Expand Up @@ -77,7 +78,7 @@ pub fn op_to_const<'tcx>(
let normalized_op = if normalize {
ecx.try_read_immediate(op)?
} else {
match op.op {
match *op {
Operand::Indirect(mplace) => Err(mplace),
Operand::Immediate(val) => Ok(val)
}
Expand Down Expand Up @@ -105,15 +106,6 @@ pub fn op_to_const<'tcx>(
Ok(ty::Const { val, ty: op.layout.ty })
}

pub fn lazy_const_to_op<'tcx>(
ecx: &CompileTimeEvalContext<'_, '_, 'tcx>,
cnst: ty::LazyConst<'tcx>,
ty: ty::Ty<'tcx>,
) -> EvalResult<'tcx, OpTy<'tcx>> {
let op = ecx.const_value_to_op(cnst)?;
Ok(OpTy { op, layout: ecx.layout_of(ty)? })
}

fn eval_body_and_ecx<'a, 'mir, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
cid: GlobalId<'tcx>,
Expand Down Expand Up @@ -388,10 +380,8 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
fn ptr_op(
_ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
_bin_op: mir::BinOp,
_left: Scalar,
_left_layout: TyLayout<'tcx>,
_right: Scalar,
_right_layout: TyLayout<'tcx>,
_left: ImmTy<'tcx>,
_right: ImmTy<'tcx>,
) -> EvalResult<'tcx, (Scalar, bool)> {
Err(
ConstEvalError::NeedsRfc("pointer arithmetic or comparison".to_string()).into(),
Expand Down Expand Up @@ -486,7 +476,7 @@ pub fn const_field<'a, 'tcx>(
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env);
let result = (|| {
// get the operand again
let op = lazy_const_to_op(&ecx, ty::LazyConst::Evaluated(value), value.ty)?;
let op = ecx.lazy_const_to_op(ty::LazyConst::Evaluated(value), value.ty)?;
// downcast
let down = match variant {
None => op,
Expand All @@ -512,7 +502,7 @@ pub fn const_variant_index<'a, 'tcx>(
) -> EvalResult<'tcx, VariantIdx> {
trace!("const_variant_index: {:?}", val);
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env);
let op = lazy_const_to_op(&ecx, ty::LazyConst::Evaluated(val), val.ty)?;
let op = ecx.lazy_const_to_op(ty::LazyConst::Evaluated(val), val.ty)?;
Ok(ecx.read_discriminant(op)?.1)
}

Expand Down
4 changes: 2 additions & 2 deletions src/librustc_mir/interpret/cast.rs
Expand Up @@ -9,7 +9,7 @@ use rustc::mir::interpret::{
use rustc::mir::CastKind;
use rustc_apfloat::Float;

use super::{EvalContext, Machine, PlaceTy, OpTy, Immediate};
use super::{EvalContext, Machine, PlaceTy, OpTy, ImmTy, Immediate};

impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
fn type_is_fat_ptr(&self, ty: Ty<'tcx>) -> bool {
Expand Down Expand Up @@ -372,7 +372,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
assert_eq!(src.layout.fields.offset(i).bytes(), 0);
assert_eq!(src_field_layout.size, src.layout.size);
// just sawp out the layout
OpTy { op: src.op, layout: src_field_layout }
OpTy::from(ImmTy { imm: src.to_immediate(), layout: src_field_layout })
}
};
if src_field.layout.ty == dst_field.layout.ty {
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_mir/interpret/intrinsics.rs
Expand Up @@ -126,7 +126,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
let l = self.read_immediate(args[0])?;
let r = self.read_immediate(args[1])?;
let is_add = intrinsic_name == "saturating_add";
let (val, overflowed) = self.binary_op_imm(if is_add {
let (val, overflowed) = self.binary_op(if is_add {
BinOp::Add
} else {
BinOp::Sub
Expand Down Expand Up @@ -173,7 +173,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
"unchecked_shr" => BinOp::Shr,
_ => bug!("Already checked for int ops")
};
let (val, overflowed) = self.binary_op_imm(bin_op, l, r)?;
let (val, overflowed) = self.binary_op(bin_op, l, r)?;
if overflowed {
let layout = self.layout_of(substs.type_at(0))?;
let r_val = r.to_scalar()?.to_bits(layout.size)?;
Expand Down
10 changes: 4 additions & 6 deletions src/librustc_mir/interpret/machine.rs
Expand Up @@ -7,11 +7,11 @@ use std::hash::Hash;

use rustc::hir::{self, def_id::DefId};
use rustc::mir;
use rustc::ty::{self, layout::TyLayout, query::TyCtxtAt};
use rustc::ty::{self, query::TyCtxtAt};

use super::{
Allocation, AllocId, EvalResult, Scalar, AllocationExtra,
EvalContext, PlaceTy, MPlaceTy, OpTy, Pointer, MemoryKind,
EvalContext, PlaceTy, MPlaceTy, OpTy, ImmTy, Pointer, MemoryKind,
};

/// Whether this kind of memory is allowed to leak
Expand Down Expand Up @@ -158,10 +158,8 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
fn ptr_op(
ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
bin_op: mir::BinOp,
left: Scalar<Self::PointerTag>,
left_layout: TyLayout<'tcx>,
right: Scalar<Self::PointerTag>,
right_layout: TyLayout<'tcx>,
left: ImmTy<'tcx, Self::PointerTag>,
right: ImmTy<'tcx, Self::PointerTag>,
) -> EvalResult<'tcx, (Scalar<Self::PointerTag>, bool)>;

/// Heap allocations via the `box` keyword.
Expand Down
75 changes: 64 additions & 11 deletions src/librustc_mir/interpret/operand.rs
Expand Up @@ -11,7 +11,10 @@ use rustc::mir::interpret::{
ConstValue, Pointer, Scalar,
EvalResult, EvalErrorKind,
};
use super::{EvalContext, Machine, MemPlace, MPlaceTy, MemoryKind};
use super::{
EvalContext, Machine, AllocMap, Allocation, AllocationExtra,
MemPlace, MPlaceTy, PlaceTy, Place, MemoryKind,
};
pub use rustc::mir::interpret::ScalarMaybeUndef;

/// A `Value` represents a single immediate self-contained Rust value.
Expand Down Expand Up @@ -41,6 +44,11 @@ impl Immediate {
}

impl<'tcx, Tag> Immediate<Tag> {
#[inline]
pub fn from_scalar(val: Scalar<Tag>) -> Self {
Immediate::Scalar(ScalarMaybeUndef::Scalar(val))
}

#[inline]
pub fn erase_tag(self) -> Immediate
{
Expand Down Expand Up @@ -112,15 +120,15 @@ impl<'tcx, Tag> Immediate<Tag> {
// as input for binary and cast operations.
#[derive(Copy, Clone, Debug)]
pub struct ImmTy<'tcx, Tag=()> {
immediate: Immediate<Tag>,
pub imm: Immediate<Tag>,
pub layout: TyLayout<'tcx>,
}

impl<'tcx, Tag> ::std::ops::Deref for ImmTy<'tcx, Tag> {
type Target = Immediate<Tag>;
#[inline(always)]
fn deref(&self) -> &Immediate<Tag> {
&self.immediate
&self.imm
}
}

Expand Down Expand Up @@ -180,7 +188,7 @@ impl<Tag> Operand<Tag> {

#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub struct OpTy<'tcx, Tag=()> {
crate op: Operand<Tag>, // ideally we'd make this private, but const_prop needs this
op: Operand<Tag>,
pub layout: TyLayout<'tcx>,
}

Expand All @@ -206,12 +214,25 @@ impl<'tcx, Tag> From<ImmTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
#[inline(always)]
fn from(val: ImmTy<'tcx, Tag>) -> Self {
OpTy {
op: Operand::Immediate(val.immediate),
op: Operand::Immediate(val.imm),
layout: val.layout
}
}
}

impl<'tcx, Tag: Copy> ImmTy<'tcx, Tag>
{
#[inline]
pub fn from_scalar(val: Scalar<Tag>, layout: TyLayout<'tcx>) -> Self {
ImmTy { imm: Immediate::from_scalar(val), layout }
}

#[inline]
pub fn to_bits(self) -> EvalResult<'tcx, u128> {
self.to_scalar()?.to_bits(self.layout.size)
}
}

impl<'tcx, Tag> OpTy<'tcx, Tag>
{
#[inline]
Expand Down Expand Up @@ -324,8 +345,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
&self,
op: OpTy<'tcx, M::PointerTag>
) -> EvalResult<'tcx, ImmTy<'tcx, M::PointerTag>> {
if let Ok(immediate) = self.try_read_immediate(op)? {
Ok(ImmTy { immediate, layout: op.layout })
if let Ok(imm) = self.try_read_immediate(op)? {
Ok(ImmTy { imm, layout: op.layout })
} else {
bug!("primitive read failed for type: {:?}", op.layout.ty);
}
Expand Down Expand Up @@ -469,6 +490,22 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
Ok(OpTy { op, layout })
}

/// Every place can be read from, so we can turm them into an operand
#[inline(always)]
pub fn place_to_op(
&self,
place: PlaceTy<'tcx, M::PointerTag>
) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
let op = match *place {
Place::Ptr(mplace) => {
Operand::Indirect(mplace)
}
Place::Local { frame, local } =>
*self.stack[frame].locals[local].access()?
};
Ok(OpTy { op, layout: place.layout })
}

// Evaluate a place with the goal of reading from it. This lets us sometimes
// avoid allocations.
fn eval_place_to_op(
Expand Down Expand Up @@ -531,10 +568,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
.collect()
}

// Used when miri runs into a constant, and by CTFE.
// FIXME: CTFE should use allocations, then we can make this private (embed it into
// `eval_operand`, ideally).
pub(crate) fn const_value_to_op(
// Used when Miri runs into a constant, and (indirectly through lazy_const_to_op) by CTFE.
fn const_value_to_op(
&self,
val: ty::LazyConst<'tcx>,
) -> EvalResult<'tcx, Operand<M::PointerTag>> {
Expand Down Expand Up @@ -666,3 +701,21 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
}

}

impl<'a, 'mir, 'tcx, M> EvalContext<'a, 'mir, 'tcx, M>
where
M: Machine<'a, 'mir, 'tcx, PointerTag=()>,
// FIXME: Working around https://github.com/rust-lang/rust/issues/24159
M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation<(), M::AllocExtra>)>,
M::AllocExtra: AllocationExtra<(), M::MemoryExtra>,
{
// FIXME: CTFE should use allocations, then we can remove this.
pub(crate) fn lazy_const_to_op(
&self,
cnst: ty::LazyConst<'tcx>,
ty: ty::Ty<'tcx>,
) -> EvalResult<'tcx, OpTy<'tcx>> {
let op = self.const_value_to_op(cnst)?;
Ok(OpTy { op, layout: self.layout_of(ty)? })
}
}

0 comments on commit fab0f9b

Please sign in to comment.