1
1
use rustc::mir;
2
- use rustc::ty::{self, layout::TyLayout};
2
+ use rustc::ty::{self, Ty, layout::{ TyLayout, LayoutOf} };
3
3
use syntax::ast::FloatTy;
4
4
use rustc_apfloat::Float;
5
5
use rustc::mir::interpret::{InterpResult, Scalar};
@@ -17,7 +17,12 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
17
17
right: ImmTy<'tcx, M::PointerTag>,
18
18
dest: PlaceTy<'tcx, M::PointerTag>,
19
19
) -> InterpResult<'tcx> {
20
- let (val, overflowed) = self.binary_op(op, left, right)?;
20
+ let (val, overflowed, ty) = self.overflowing_binary_op(op, left, right)?;
21
+ debug_assert_eq!(
22
+ self.tcx.intern_tup(&[ty, self.tcx.types.bool]),
23
+ dest.layout.ty,
24
+ "type mismatch for result of {:?}", op,
25
+ );
21
26
let val = Immediate::ScalarPair(val.into(), Scalar::from_bool(overflowed).into());
22
27
self.write_immediate(val, dest)
23
28
}
@@ -31,7 +36,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
31
36
right: ImmTy<'tcx, M::PointerTag>,
32
37
dest: PlaceTy<'tcx, M::PointerTag>,
33
38
) -> InterpResult<'tcx> {
34
- let (val, _overflowed) = self.binary_op(op, left, right)?;
39
+ let (val, _overflowed, ty) = self.overflowing_binary_op(op, left, right)?;
40
+ assert_eq!(ty, dest.layout.ty, "type mismatch for result of {:?}", op);
35
41
self.write_scalar(val, dest)
36
42
}
37
43
}
@@ -42,7 +48,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
42
48
bin_op: mir::BinOp,
43
49
l: char,
44
50
r: char,
45
- ) -> (Scalar<M::PointerTag>, bool) {
51
+ ) -> (Scalar<M::PointerTag>, bool, Ty<'tcx> ) {
46
52
use rustc::mir::BinOp::*;
47
53
48
54
let res = match bin_op {
@@ -54,15 +60,15 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
54
60
Ge => l >= r,
55
61
_ => bug!("Invalid operation on char: {:?}", bin_op),
56
62
};
57
- return (Scalar::from_bool(res), false);
63
+ return (Scalar::from_bool(res), false, self.tcx.types.bool );
58
64
}
59
65
60
66
fn binary_bool_op(
61
67
&self,
62
68
bin_op: mir::BinOp,
63
69
l: bool,
64
70
r: bool,
65
- ) -> (Scalar<M::PointerTag>, bool) {
71
+ ) -> (Scalar<M::PointerTag>, bool, Ty<'tcx> ) {
66
72
use rustc::mir::BinOp::*;
67
73
68
74
let res = match bin_op {
@@ -77,32 +83,33 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
77
83
BitXor => l ^ r,
78
84
_ => bug!("Invalid operation on bool: {:?}", bin_op),
79
85
};
80
- return (Scalar::from_bool(res), false);
86
+ return (Scalar::from_bool(res), false, self.tcx.types.bool );
81
87
}
82
88
83
89
fn binary_float_op<F: Float + Into<Scalar<M::PointerTag>>>(
84
90
&self,
85
91
bin_op: mir::BinOp,
92
+ ty: Ty<'tcx>,
86
93
l: F,
87
94
r: F,
88
- ) -> (Scalar<M::PointerTag>, bool) {
95
+ ) -> (Scalar<M::PointerTag>, bool, Ty<'tcx> ) {
89
96
use rustc::mir::BinOp::*;
90
97
91
- let val = match bin_op {
92
- Eq => Scalar::from_bool(l == r),
93
- Ne => Scalar::from_bool(l != r),
94
- Lt => Scalar::from_bool(l < r),
95
- Le => Scalar::from_bool(l <= r),
96
- Gt => Scalar::from_bool(l > r),
97
- Ge => Scalar::from_bool(l >= r),
98
- Add => (l + r).value.into(),
99
- Sub => (l - r).value.into(),
100
- Mul => (l * r).value.into(),
101
- Div => (l / r).value.into(),
102
- Rem => (l % r).value.into(),
98
+ let ( val, ty) = match bin_op {
99
+ Eq => ( Scalar::from_bool(l == r), self.tcx.types.bool ),
100
+ Ne => ( Scalar::from_bool(l != r), self.tcx.types.bool ),
101
+ Lt => ( Scalar::from_bool(l < r), self.tcx.types.bool ),
102
+ Le => ( Scalar::from_bool(l <= r), self.tcx.types.bool ),
103
+ Gt => ( Scalar::from_bool(l > r), self.tcx.types.bool ),
104
+ Ge => ( Scalar::from_bool(l >= r), self.tcx.types.bool ),
105
+ Add => (( l + r).value.into(), ty ),
106
+ Sub => (( l - r).value.into(), ty ),
107
+ Mul => (( l * r).value.into(), ty ),
108
+ Div => (( l / r).value.into(), ty ),
109
+ Rem => (( l % r).value.into(), ty ),
103
110
_ => bug!("invalid float op: `{:?}`", bin_op),
104
111
};
105
- return (val, false);
112
+ return (val, false, ty );
106
113
}
107
114
108
115
fn binary_int_op(
@@ -113,7 +120,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
113
120
left_layout: TyLayout<'tcx>,
114
121
r: u128,
115
122
right_layout: TyLayout<'tcx>,
116
- ) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool)> {
123
+ ) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool, Ty<'tcx> )> {
117
124
use rustc::mir::BinOp::*;
118
125
119
126
// Shift ops can have an RHS with a different numeric type.
@@ -142,7 +149,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
142
149
}
143
150
};
144
151
let truncated = self.truncate(result, left_layout);
145
- return Ok((Scalar::from_uint(truncated, size), oflo));
152
+ return Ok((Scalar::from_uint(truncated, size), oflo, left_layout.ty ));
146
153
}
147
154
148
155
// For the remaining ops, the types must be the same on both sides
@@ -167,7 +174,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
167
174
if let Some(op) = op {
168
175
let l = self.sign_extend(l, left_layout) as i128;
169
176
let r = self.sign_extend(r, right_layout) as i128;
170
- return Ok((Scalar::from_bool(op(&l, &r)), false));
177
+ return Ok((Scalar::from_bool(op(&l, &r)), false, self.tcx.types.bool ));
171
178
}
172
179
let op: Option<fn(i128, i128) -> (i128, bool)> = match bin_op {
173
180
Div if r == 0 => throw_panic!(DivisionByZero),
@@ -187,7 +194,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
187
194
Rem | Div => {
188
195
// int_min / -1
189
196
if r == -1 && l == (1 << (size.bits() - 1)) {
190
- return Ok((Scalar::from_uint(l, size), true));
197
+ return Ok((Scalar::from_uint(l, size), true, left_layout.ty ));
191
198
}
192
199
},
193
200
_ => {},
@@ -202,25 +209,24 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
202
209
// this may be out-of-bounds for the result type, so we have to truncate ourselves
203
210
let result = result as u128;
204
211
let truncated = self.truncate(result, left_layout);
205
- return Ok((Scalar::from_uint(truncated, size), oflo));
212
+ return Ok((Scalar::from_uint(truncated, size), oflo, left_layout.ty ));
206
213
}
207
214
}
208
215
209
216
let size = left_layout.size;
210
217
211
- // only ints left
212
- let val = match bin_op {
213
- Eq => Scalar::from_bool(l == r),
214
- Ne => Scalar::from_bool(l != r),
218
+ let (val, ty) = match bin_op {
219
+ Eq => (Scalar::from_bool(l == r), self.tcx.types.bool),
220
+ Ne => (Scalar::from_bool(l != r), self.tcx.types.bool),
215
221
216
- Lt => Scalar::from_bool(l < r),
217
- Le => Scalar::from_bool(l <= r),
218
- Gt => Scalar::from_bool(l > r),
219
- Ge => Scalar::from_bool(l >= r),
222
+ Lt => ( Scalar::from_bool(l < r), self.tcx.types.bool ),
223
+ Le => ( Scalar::from_bool(l <= r), self.tcx.types.bool ),
224
+ Gt => ( Scalar::from_bool(l > r), self.tcx.types.bool ),
225
+ Ge => ( Scalar::from_bool(l >= r), self.tcx.types.bool ),
220
226
221
- BitOr => Scalar::from_uint(l | r, size),
222
- BitAnd => Scalar::from_uint(l & r, size),
223
- BitXor => Scalar::from_uint(l ^ r, size),
227
+ BitOr => ( Scalar::from_uint(l | r, size), left_layout.ty ),
228
+ BitAnd => ( Scalar::from_uint(l & r, size), left_layout.ty ),
229
+ BitXor => ( Scalar::from_uint(l ^ r, size), left_layout.ty ),
224
230
225
231
Add | Sub | Mul | Rem | Div => {
226
232
debug_assert!(!left_layout.abi.is_signed());
@@ -236,7 +242,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
236
242
};
237
243
let (result, oflo) = op(l, r);
238
244
let truncated = self.truncate(result, left_layout);
239
- return Ok((Scalar::from_uint(truncated, size), oflo || truncated != result));
245
+ return Ok((
246
+ Scalar::from_uint(truncated, size),
247
+ oflo || truncated != result,
248
+ left_layout.ty,
249
+ ));
240
250
}
241
251
242
252
_ => {
@@ -250,17 +260,17 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
250
260
}
251
261
};
252
262
253
- Ok((val, false))
263
+ Ok((val, false, ty ))
254
264
}
255
265
256
- /// Returns the result of the specified operation and whether it overflowed.
257
- #[inline]
258
- pub fn binary_op (
266
+ /// Returns the result of the specified operation, whether it overflowed, and
267
+ /// the result type.
268
+ pub fn overflowing_binary_op (
259
269
&self,
260
270
bin_op: mir::BinOp,
261
271
left: ImmTy<'tcx, M::PointerTag>,
262
272
right: ImmTy<'tcx, M::PointerTag>,
263
- ) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool)> {
273
+ ) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool, Ty<'tcx> )> {
264
274
trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
265
275
bin_op, *left, left.layout.ty, *right, right.layout.ty);
266
276
@@ -279,11 +289,14 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
279
289
}
280
290
ty::Float(fty) => {
281
291
assert_eq!(left.layout.ty, right.layout.ty);
292
+ let ty = left.layout.ty;
282
293
let left = left.to_scalar()?;
283
294
let right = right.to_scalar()?;
284
295
Ok(match fty {
285
- FloatTy::F32 => self.binary_float_op(bin_op, left.to_f32()?, right.to_f32()?),
286
- FloatTy::F64 => self.binary_float_op(bin_op, left.to_f64()?, right.to_f64()?),
296
+ FloatTy::F32 =>
297
+ self.binary_float_op(bin_op, ty, left.to_f32()?, right.to_f32()?),
298
+ FloatTy::F64 =>
299
+ self.binary_float_op(bin_op, ty, left.to_f64()?, right.to_f64()?),
287
300
})
288
301
}
289
302
_ if left.layout.ty.is_integral() => {
@@ -312,11 +325,23 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
312
325
}
313
326
}
314
327
328
+ /// Typed version of `checked_binary_op`, returning an `ImmTy`. Also ignores overflows.
329
+ #[inline]
330
+ pub fn binary_op(
331
+ &self,
332
+ bin_op: mir::BinOp,
333
+ left: ImmTy<'tcx, M::PointerTag>,
334
+ right: ImmTy<'tcx, M::PointerTag>,
335
+ ) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> {
336
+ let (val, _overflow, ty) = self.overflowing_binary_op(bin_op, left, right)?;
337
+ Ok(ImmTy::from_scalar(val, self.layout_of(ty)?))
338
+ }
339
+
315
340
pub fn unary_op(
316
341
&self,
317
342
un_op: mir::UnOp,
318
343
val: ImmTy<'tcx, M::PointerTag>,
319
- ) -> InterpResult<'tcx, Scalar< M::PointerTag>> {
344
+ ) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> {
320
345
use rustc::mir::UnOp::*;
321
346
322
347
let layout = val.layout;
@@ -330,15 +355,15 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
330
355
Not => !val,
331
356
_ => bug!("Invalid bool op {:?}", un_op)
332
357
};
333
- Ok(Scalar::from_bool(res))
358
+ Ok(ImmTy::from_scalar( Scalar::from_bool(res), self.layout_of(self.tcx.types.bool)? ))
334
359
}
335
360
ty::Float(fty) => {
336
361
let res = match (un_op, fty) {
337
362
(Neg, FloatTy::F32) => Scalar::from_f32(-val.to_f32()?),
338
363
(Neg, FloatTy::F64) => Scalar::from_f64(-val.to_f64()?),
339
364
_ => bug!("Invalid float op {:?}", un_op)
340
365
};
341
- Ok(res)
366
+ Ok(ImmTy::from_scalar( res, layout) )
342
367
}
343
368
_ => {
344
369
assert!(layout.ty.is_integral());
@@ -351,7 +376,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
351
376
}
352
377
};
353
378
// res needs tuncating
354
- Ok(Scalar ::from_uint(self.truncate(res, layout), layout.size ))
379
+ Ok(ImmTy ::from_uint(self.truncate(res, layout), layout))
355
380
}
356
381
}
357
382
}
0 commit comments