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