Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable comparing fat pointers #58301

Merged
merged 4 commits into from
Feb 14, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 8 additions & 18 deletions src/librustc_mir/const_eval.rs
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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)? })
}
}
Loading