Skip to content

Commit fab0f9b

Browse files
authored
Rollup merge of #58301 - RalfJung:fat-ptr-eq, r=oli-obk
Enable comparing fat pointers Also refactor our binops a bit to make that happen more easily. r? @oli-obk
2 parents 56e1916 + 22d5e6a commit fab0f9b

File tree

11 files changed

+146
-130
lines changed

11 files changed

+146
-130
lines changed

src/librustc_mir/const_eval.rs

+8-18
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use rustc::hir::def::Def;
1111
use rustc::mir::interpret::{ConstEvalErr, ErrorHandled};
1212
use rustc::mir;
1313
use rustc::ty::{self, TyCtxt, query::TyCtxtAt};
14-
use rustc::ty::layout::{self, LayoutOf, TyLayout, VariantIdx};
14+
use rustc::ty::layout::{self, LayoutOf, VariantIdx};
1515
use rustc::ty::subst::Subst;
1616
use rustc::traits::Reveal;
1717
use rustc_data_structures::fx::FxHashMap;
@@ -21,7 +21,8 @@ use syntax::ast::Mutability;
2121
use syntax::source_map::{Span, DUMMY_SP};
2222

2323
use crate::interpret::{self,
24-
PlaceTy, MPlaceTy, MemPlace, OpTy, Operand, Immediate, Scalar, RawConst, ConstValue, Pointer,
24+
PlaceTy, MPlaceTy, MemPlace, OpTy, ImmTy, Operand, Immediate, Scalar, Pointer,
25+
RawConst, ConstValue,
2526
EvalResult, EvalError, EvalErrorKind, GlobalId, EvalContext, StackPopCleanup,
2627
Allocation, AllocId, MemoryKind,
2728
snapshot, RefTracking,
@@ -77,7 +78,7 @@ pub fn op_to_const<'tcx>(
7778
let normalized_op = if normalize {
7879
ecx.try_read_immediate(op)?
7980
} else {
80-
match op.op {
81+
match *op {
8182
Operand::Indirect(mplace) => Err(mplace),
8283
Operand::Immediate(val) => Ok(val)
8384
}
@@ -105,15 +106,6 @@ pub fn op_to_const<'tcx>(
105106
Ok(ty::Const { val, ty: op.layout.ty })
106107
}
107108

108-
pub fn lazy_const_to_op<'tcx>(
109-
ecx: &CompileTimeEvalContext<'_, '_, 'tcx>,
110-
cnst: ty::LazyConst<'tcx>,
111-
ty: ty::Ty<'tcx>,
112-
) -> EvalResult<'tcx, OpTy<'tcx>> {
113-
let op = ecx.const_value_to_op(cnst)?;
114-
Ok(OpTy { op, layout: ecx.layout_of(ty)? })
115-
}
116-
117109
fn eval_body_and_ecx<'a, 'mir, 'tcx>(
118110
tcx: TyCtxt<'a, 'tcx, 'tcx>,
119111
cid: GlobalId<'tcx>,
@@ -388,10 +380,8 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
388380
fn ptr_op(
389381
_ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
390382
_bin_op: mir::BinOp,
391-
_left: Scalar,
392-
_left_layout: TyLayout<'tcx>,
393-
_right: Scalar,
394-
_right_layout: TyLayout<'tcx>,
383+
_left: ImmTy<'tcx>,
384+
_right: ImmTy<'tcx>,
395385
) -> EvalResult<'tcx, (Scalar, bool)> {
396386
Err(
397387
ConstEvalError::NeedsRfc("pointer arithmetic or comparison".to_string()).into(),
@@ -486,7 +476,7 @@ pub fn const_field<'a, 'tcx>(
486476
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env);
487477
let result = (|| {
488478
// get the operand again
489-
let op = lazy_const_to_op(&ecx, ty::LazyConst::Evaluated(value), value.ty)?;
479+
let op = ecx.lazy_const_to_op(ty::LazyConst::Evaluated(value), value.ty)?;
490480
// downcast
491481
let down = match variant {
492482
None => op,
@@ -512,7 +502,7 @@ pub fn const_variant_index<'a, 'tcx>(
512502
) -> EvalResult<'tcx, VariantIdx> {
513503
trace!("const_variant_index: {:?}", val);
514504
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env);
515-
let op = lazy_const_to_op(&ecx, ty::LazyConst::Evaluated(val), val.ty)?;
505+
let op = ecx.lazy_const_to_op(ty::LazyConst::Evaluated(val), val.ty)?;
516506
Ok(ecx.read_discriminant(op)?.1)
517507
}
518508

src/librustc_mir/interpret/cast.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc::mir::interpret::{
99
use rustc::mir::CastKind;
1010
use rustc_apfloat::Float;
1111

12-
use super::{EvalContext, Machine, PlaceTy, OpTy, Immediate};
12+
use super::{EvalContext, Machine, PlaceTy, OpTy, ImmTy, Immediate};
1313

1414
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
1515
fn type_is_fat_ptr(&self, ty: Ty<'tcx>) -> bool {
@@ -372,7 +372,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
372372
assert_eq!(src.layout.fields.offset(i).bytes(), 0);
373373
assert_eq!(src_field_layout.size, src.layout.size);
374374
// just sawp out the layout
375-
OpTy { op: src.op, layout: src_field_layout }
375+
OpTy::from(ImmTy { imm: src.to_immediate(), layout: src_field_layout })
376376
}
377377
};
378378
if src_field.layout.ty == dst_field.layout.ty {

src/librustc_mir/interpret/intrinsics.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
126126
let l = self.read_immediate(args[0])?;
127127
let r = self.read_immediate(args[1])?;
128128
let is_add = intrinsic_name == "saturating_add";
129-
let (val, overflowed) = self.binary_op_imm(if is_add {
129+
let (val, overflowed) = self.binary_op(if is_add {
130130
BinOp::Add
131131
} else {
132132
BinOp::Sub
@@ -173,7 +173,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
173173
"unchecked_shr" => BinOp::Shr,
174174
_ => bug!("Already checked for int ops")
175175
};
176-
let (val, overflowed) = self.binary_op_imm(bin_op, l, r)?;
176+
let (val, overflowed) = self.binary_op(bin_op, l, r)?;
177177
if overflowed {
178178
let layout = self.layout_of(substs.type_at(0))?;
179179
let r_val = r.to_scalar()?.to_bits(layout.size)?;

src/librustc_mir/interpret/machine.rs

+4-6
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ use std::hash::Hash;
77

88
use rustc::hir::{self, def_id::DefId};
99
use rustc::mir;
10-
use rustc::ty::{self, layout::TyLayout, query::TyCtxtAt};
10+
use rustc::ty::{self, query::TyCtxtAt};
1111

1212
use super::{
1313
Allocation, AllocId, EvalResult, Scalar, AllocationExtra,
14-
EvalContext, PlaceTy, MPlaceTy, OpTy, Pointer, MemoryKind,
14+
EvalContext, PlaceTy, MPlaceTy, OpTy, ImmTy, Pointer, MemoryKind,
1515
};
1616

1717
/// Whether this kind of memory is allowed to leak
@@ -158,10 +158,8 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
158158
fn ptr_op(
159159
ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
160160
bin_op: mir::BinOp,
161-
left: Scalar<Self::PointerTag>,
162-
left_layout: TyLayout<'tcx>,
163-
right: Scalar<Self::PointerTag>,
164-
right_layout: TyLayout<'tcx>,
161+
left: ImmTy<'tcx, Self::PointerTag>,
162+
right: ImmTy<'tcx, Self::PointerTag>,
165163
) -> EvalResult<'tcx, (Scalar<Self::PointerTag>, bool)>;
166164

167165
/// Heap allocations via the `box` keyword.

src/librustc_mir/interpret/operand.rs

+64-11
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ use rustc::mir::interpret::{
1111
ConstValue, Pointer, Scalar,
1212
EvalResult, EvalErrorKind,
1313
};
14-
use super::{EvalContext, Machine, MemPlace, MPlaceTy, MemoryKind};
14+
use super::{
15+
EvalContext, Machine, AllocMap, Allocation, AllocationExtra,
16+
MemPlace, MPlaceTy, PlaceTy, Place, MemoryKind,
17+
};
1518
pub use rustc::mir::interpret::ScalarMaybeUndef;
1619

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

4346
impl<'tcx, Tag> Immediate<Tag> {
47+
#[inline]
48+
pub fn from_scalar(val: Scalar<Tag>) -> Self {
49+
Immediate::Scalar(ScalarMaybeUndef::Scalar(val))
50+
}
51+
4452
#[inline]
4553
pub fn erase_tag(self) -> Immediate
4654
{
@@ -112,15 +120,15 @@ impl<'tcx, Tag> Immediate<Tag> {
112120
// as input for binary and cast operations.
113121
#[derive(Copy, Clone, Debug)]
114122
pub struct ImmTy<'tcx, Tag=()> {
115-
immediate: Immediate<Tag>,
123+
pub imm: Immediate<Tag>,
116124
pub layout: TyLayout<'tcx>,
117125
}
118126

119127
impl<'tcx, Tag> ::std::ops::Deref for ImmTy<'tcx, Tag> {
120128
type Target = Immediate<Tag>;
121129
#[inline(always)]
122130
fn deref(&self) -> &Immediate<Tag> {
123-
&self.immediate
131+
&self.imm
124132
}
125133
}
126134

@@ -180,7 +188,7 @@ impl<Tag> Operand<Tag> {
180188

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

@@ -206,12 +214,25 @@ impl<'tcx, Tag> From<ImmTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
206214
#[inline(always)]
207215
fn from(val: ImmTy<'tcx, Tag>) -> Self {
208216
OpTy {
209-
op: Operand::Immediate(val.immediate),
217+
op: Operand::Immediate(val.imm),
210218
layout: val.layout
211219
}
212220
}
213221
}
214222

223+
impl<'tcx, Tag: Copy> ImmTy<'tcx, Tag>
224+
{
225+
#[inline]
226+
pub fn from_scalar(val: Scalar<Tag>, layout: TyLayout<'tcx>) -> Self {
227+
ImmTy { imm: Immediate::from_scalar(val), layout }
228+
}
229+
230+
#[inline]
231+
pub fn to_bits(self) -> EvalResult<'tcx, u128> {
232+
self.to_scalar()?.to_bits(self.layout.size)
233+
}
234+
}
235+
215236
impl<'tcx, Tag> OpTy<'tcx, Tag>
216237
{
217238
#[inline]
@@ -324,8 +345,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
324345
&self,
325346
op: OpTy<'tcx, M::PointerTag>
326347
) -> EvalResult<'tcx, ImmTy<'tcx, M::PointerTag>> {
327-
if let Ok(immediate) = self.try_read_immediate(op)? {
328-
Ok(ImmTy { immediate, layout: op.layout })
348+
if let Ok(imm) = self.try_read_immediate(op)? {
349+
Ok(ImmTy { imm, layout: op.layout })
329350
} else {
330351
bug!("primitive read failed for type: {:?}", op.layout.ty);
331352
}
@@ -469,6 +490,22 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
469490
Ok(OpTy { op, layout })
470491
}
471492

493+
/// Every place can be read from, so we can turm them into an operand
494+
#[inline(always)]
495+
pub fn place_to_op(
496+
&self,
497+
place: PlaceTy<'tcx, M::PointerTag>
498+
) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
499+
let op = match *place {
500+
Place::Ptr(mplace) => {
501+
Operand::Indirect(mplace)
502+
}
503+
Place::Local { frame, local } =>
504+
*self.stack[frame].locals[local].access()?
505+
};
506+
Ok(OpTy { op, layout: place.layout })
507+
}
508+
472509
// Evaluate a place with the goal of reading from it. This lets us sometimes
473510
// avoid allocations.
474511
fn eval_place_to_op(
@@ -531,10 +568,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
531568
.collect()
532569
}
533570

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

668703
}
704+
705+
impl<'a, 'mir, 'tcx, M> EvalContext<'a, 'mir, 'tcx, M>
706+
where
707+
M: Machine<'a, 'mir, 'tcx, PointerTag=()>,
708+
// FIXME: Working around https://github.com/rust-lang/rust/issues/24159
709+
M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation<(), M::AllocExtra>)>,
710+
M::AllocExtra: AllocationExtra<(), M::MemoryExtra>,
711+
{
712+
// FIXME: CTFE should use allocations, then we can remove this.
713+
pub(crate) fn lazy_const_to_op(
714+
&self,
715+
cnst: ty::LazyConst<'tcx>,
716+
ty: ty::Ty<'tcx>,
717+
) -> EvalResult<'tcx, OpTy<'tcx>> {
718+
let op = self.const_value_to_op(cnst)?;
719+
Ok(OpTy { op, layout: self.layout_of(ty)? })
720+
}
721+
}

0 commit comments

Comments
 (0)