Skip to content

Commit b376ae6

Browse files
committed
make bin_op and unary_op APIs consistently work on ImmTy
1 parent e73f96a commit b376ae6

File tree

8 files changed

+66
-65
lines changed

8 files changed

+66
-65
lines changed

src/librustc_mir/const_eval.rs

+5-6
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,
@@ -379,10 +380,8 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
379380
fn ptr_op(
380381
_ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
381382
_bin_op: mir::BinOp,
382-
_left: Scalar,
383-
_left_layout: TyLayout<'tcx>,
384-
_right: Scalar,
385-
_right_layout: TyLayout<'tcx>,
383+
_left: ImmTy<'tcx>,
384+
_right: ImmTy<'tcx>,
386385
) -> EvalResult<'tcx, (Scalar, bool)> {
387386
Err(
388387
ConstEvalError::NeedsRfc("pointer arithmetic or comparison".to_string()).into(),

src/librustc_mir/interpret/intrinsics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -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

+19-1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ impl Immediate {
4444
}
4545

4646
impl<'tcx, Tag> Immediate<Tag> {
47+
#[inline]
48+
pub fn from_scalar(val: Scalar<Tag>) -> Self {
49+
Immediate::Scalar(ScalarMaybeUndef::Scalar(val))
50+
}
51+
4752
#[inline]
4853
pub fn erase_tag(self) -> Immediate
4954
{
@@ -115,7 +120,7 @@ impl<'tcx, Tag> Immediate<Tag> {
115120
// as input for binary and cast operations.
116121
#[derive(Copy, Clone, Debug)]
117122
pub struct ImmTy<'tcx, Tag=()> {
118-
crate imm: Immediate<Tag>, // ideally we'd make this private, but const_prop needs this
123+
pub imm: Immediate<Tag>,
119124
pub layout: TyLayout<'tcx>,
120125
}
121126

@@ -215,6 +220,19 @@ impl<'tcx, Tag> From<ImmTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
215220
}
216221
}
217222

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+
218236
impl<'tcx, Tag> OpTy<'tcx, Tag>
219237
{
220238
#[inline]

src/librustc_mir/interpret/operator.rs

+30-43
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
1818
right: ImmTy<'tcx, M::PointerTag>,
1919
dest: PlaceTy<'tcx, M::PointerTag>,
2020
) -> EvalResult<'tcx> {
21-
let (val, overflowed) = self.binary_op_imm(op, left, right)?;
21+
let (val, overflowed) = self.binary_op(op, left, right)?;
2222
let val = Immediate::ScalarPair(val.into(), Scalar::from_bool(overflowed).into());
2323
self.write_immediate(val, dest)
2424
}
@@ -32,7 +32,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
3232
right: ImmTy<'tcx, M::PointerTag>,
3333
dest: PlaceTy<'tcx, M::PointerTag>,
3434
) -> EvalResult<'tcx> {
35-
let (val, _overflowed) = self.binary_op_imm(op, left, right)?;
35+
let (val, _overflowed) = self.binary_op(op, left, right)?;
3636
self.write_scalar(val, dest)
3737
}
3838
}
@@ -272,83 +272,70 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
272272
Ok((val, false))
273273
}
274274

275-
/// Convenience wrapper that's useful when keeping the layout together with the
276-
/// immediate value.
275+
/// Returns the result of the specified operation and whether it overflowed.
277276
#[inline]
278-
pub fn binary_op_imm(
277+
pub fn binary_op(
279278
&self,
280279
bin_op: mir::BinOp,
281280
left: ImmTy<'tcx, M::PointerTag>,
282281
right: ImmTy<'tcx, M::PointerTag>,
283-
) -> EvalResult<'tcx, (Scalar<M::PointerTag>, bool)> {
284-
self.binary_op(
285-
bin_op,
286-
left.to_scalar()?, left.layout,
287-
right.to_scalar()?, right.layout,
288-
)
289-
}
290-
291-
/// Returns the result of the specified operation and whether it overflowed.
292-
pub fn binary_op(
293-
&self,
294-
bin_op: mir::BinOp,
295-
left: Scalar<M::PointerTag>,
296-
left_layout: TyLayout<'tcx>,
297-
right: Scalar<M::PointerTag>,
298-
right_layout: TyLayout<'tcx>,
299282
) -> EvalResult<'tcx, (Scalar<M::PointerTag>, bool)> {
300283
trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
301-
bin_op, left, left_layout.ty, right, right_layout.ty);
284+
bin_op, *left, left.layout.ty, *right, right.layout.ty);
302285

303-
match left_layout.ty.sty {
286+
match left.layout.ty.sty {
304287
ty::Char => {
305-
assert_eq!(left_layout.ty, right_layout.ty);
306-
let left = left.to_char()?;
307-
let right = right.to_char()?;
288+
assert_eq!(left.layout.ty, right.layout.ty);
289+
let left = left.to_scalar()?.to_char()?;
290+
let right = right.to_scalar()?.to_char()?;
308291
self.binary_char_op(bin_op, left, right)
309292
}
310293
ty::Bool => {
311-
assert_eq!(left_layout.ty, right_layout.ty);
312-
let left = left.to_bool()?;
313-
let right = right.to_bool()?;
294+
assert_eq!(left.layout.ty, right.layout.ty);
295+
let left = left.to_scalar()?.to_bool()?;
296+
let right = right.to_scalar()?.to_bool()?;
314297
self.binary_bool_op(bin_op, left, right)
315298
}
316299
ty::Float(fty) => {
317-
assert_eq!(left_layout.ty, right_layout.ty);
318-
let left = left.to_bits(left_layout.size)?;
319-
let right = right.to_bits(right_layout.size)?;
300+
assert_eq!(left.layout.ty, right.layout.ty);
301+
let left = left.to_bits()?;
302+
let right = right.to_bits()?;
320303
self.binary_float_op(bin_op, fty, left, right)
321304
}
322305
_ => {
323306
// Must be integer(-like) types. Don't forget about == on fn pointers.
324-
assert!(left_layout.ty.is_integral() || left_layout.ty.is_unsafe_ptr() ||
325-
left_layout.ty.is_fn());
326-
assert!(right_layout.ty.is_integral() || right_layout.ty.is_unsafe_ptr() ||
327-
right_layout.ty.is_fn());
307+
assert!(left.layout.ty.is_integral() || left.layout.ty.is_unsafe_ptr() ||
308+
left.layout.ty.is_fn());
309+
assert!(right.layout.ty.is_integral() || right.layout.ty.is_unsafe_ptr() ||
310+
right.layout.ty.is_fn());
328311

329312
// Handle operations that support pointer values
330-
if left.is_ptr() || right.is_ptr() || bin_op == mir::BinOp::Offset {
331-
return M::ptr_op(self, bin_op, left, left_layout, right, right_layout);
313+
if left.to_scalar_ptr()?.is_ptr() ||
314+
right.to_scalar_ptr()?.is_ptr() ||
315+
bin_op == mir::BinOp::Offset
316+
{
317+
return M::ptr_op(self, bin_op, left, right);
332318
}
333319

334320
// Everything else only works with "proper" bits
335-
let left = left.to_bits(left_layout.size).expect("we checked is_ptr");
336-
let right = right.to_bits(right_layout.size).expect("we checked is_ptr");
337-
self.binary_int_op(bin_op, left, left_layout, right, right_layout)
321+
let l = left.to_bits().expect("we checked is_ptr");
322+
let r = right.to_bits().expect("we checked is_ptr");
323+
self.binary_int_op(bin_op, l, left.layout, r, right.layout)
338324
}
339325
}
340326
}
341327

342328
pub fn unary_op(
343329
&self,
344330
un_op: mir::UnOp,
345-
val: Scalar<M::PointerTag>,
346-
layout: TyLayout<'tcx>,
331+
val: ImmTy<'tcx, M::PointerTag>,
347332
) -> EvalResult<'tcx, Scalar<M::PointerTag>> {
348333
use rustc::mir::UnOp::*;
349334
use rustc_apfloat::ieee::{Single, Double};
350335
use rustc_apfloat::Float;
351336

337+
let layout = val.layout;
338+
let val = val.to_scalar()?;
352339
trace!("Running unary op {:?}: {:?} ({:?})", un_op, val, layout.ty.sty);
353340

354341
match layout.ty.sty {

src/librustc_mir/interpret/step.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
176176
UnaryOp(un_op, ref operand) => {
177177
// The operand always has the same type as the result.
178178
let val = self.read_immediate(self.eval_operand(operand, Some(dest.layout))?)?;
179-
let val = self.unary_op(un_op, val.to_scalar()?, dest.layout)?;
179+
let val = self.unary_op(un_op, val)?;
180180
self.write_scalar(val, dest)?;
181181
}
182182

src/librustc_mir/interpret/terminator.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
5151
// Compare using binary_op, to also support pointer values
5252
let const_int = Scalar::from_uint(const_int, discr.layout.size);
5353
let (res, _) = self.binary_op(mir::BinOp::Eq,
54-
discr.to_scalar()?, discr.layout,
55-
const_int, discr.layout,
54+
discr,
55+
ImmTy::from_scalar(const_int, discr.layout),
5656
)?;
5757
if res.to_bool()? {
5858
target_block = targets[index];

src/librustc_mir/transform/const_prop.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -370,13 +370,12 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
370370

371371
let (arg, _) = self.eval_operand(arg, source_info)?;
372372
let val = self.use_ecx(source_info, |this| {
373-
let prim = this.ecx.read_scalar(arg)?.not_undef()?;
373+
let prim = this.ecx.read_immediate(arg)?;
374374
match op {
375375
UnOp::Neg => {
376376
// Need to do overflow check here: For actual CTFE, MIR
377377
// generation emits code that does this before calling the op.
378-
let size = arg.layout.size;
379-
if prim.to_bits(size)? == (1 << (size.bits() - 1)) {
378+
if prim.to_bits()? == (1 << (prim.layout.size.bits() - 1)) {
380379
return err!(OverflowNeg);
381380
}
382381
}
@@ -385,7 +384,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
385384
}
386385
}
387386
// Now run the actual operation.
388-
this.ecx.unary_op(op, prim, arg.layout)
387+
this.ecx.unary_op(op, prim)
389388
})?;
390389
let res = ImmTy {
391390
imm: Immediate::Scalar(val.into()),
@@ -446,7 +445,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
446445
})?;
447446
trace!("const evaluating {:?} for {:?} and {:?}", op, left, right);
448447
let (val, overflow) = self.use_ecx(source_info, |this| {
449-
this.ecx.binary_op_imm(op, l, r)
448+
this.ecx.binary_op(op, l, r)
450449
})?;
451450
let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue {
452451
Immediate::ScalarPair(

0 commit comments

Comments
 (0)