11use rustc:: mir;
2- use rustc:: ty:: { self , layout:: TyLayout } ;
2+ use rustc:: ty:: { self , Ty , layout:: { TyLayout , LayoutOf } } ;
33use syntax:: ast:: FloatTy ;
44use rustc_apfloat:: Float ;
55use rustc:: mir:: interpret:: { InterpResult , Scalar } ;
@@ -17,7 +17,12 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
1717 right : ImmTy < ' tcx , M :: PointerTag > ,
1818 dest : PlaceTy < ' tcx , M :: PointerTag > ,
1919 ) -> 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+ ) ;
2126 let val = Immediate :: ScalarPair ( val. into ( ) , Scalar :: from_bool ( overflowed) . into ( ) ) ;
2227 self . write_immediate ( val, dest)
2328 }
@@ -31,7 +36,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
3136 right : ImmTy < ' tcx , M :: PointerTag > ,
3237 dest : PlaceTy < ' tcx , M :: PointerTag > ,
3338 ) -> 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) ;
3541 self . write_scalar ( val, dest)
3642 }
3743}
@@ -42,7 +48,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
4248 bin_op : mir:: BinOp ,
4349 l : char ,
4450 r : char ,
45- ) -> ( Scalar < M :: PointerTag > , bool ) {
51+ ) -> ( Scalar < M :: PointerTag > , bool , Ty < ' tcx > ) {
4652 use rustc:: mir:: BinOp :: * ;
4753
4854 let res = match bin_op {
@@ -54,15 +60,15 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
5460 Ge => l >= r,
5561 _ => bug ! ( "Invalid operation on char: {:?}" , bin_op) ,
5662 } ;
57- return ( Scalar :: from_bool ( res) , false ) ;
63+ return ( Scalar :: from_bool ( res) , false , self . tcx . types . bool ) ;
5864 }
5965
6066 fn binary_bool_op (
6167 & self ,
6268 bin_op : mir:: BinOp ,
6369 l : bool ,
6470 r : bool ,
65- ) -> ( Scalar < M :: PointerTag > , bool ) {
71+ ) -> ( Scalar < M :: PointerTag > , bool , Ty < ' tcx > ) {
6672 use rustc:: mir:: BinOp :: * ;
6773
6874 let res = match bin_op {
@@ -77,32 +83,33 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
7783 BitXor => l ^ r,
7884 _ => bug ! ( "Invalid operation on bool: {:?}" , bin_op) ,
7985 } ;
80- return ( Scalar :: from_bool ( res) , false ) ;
86+ return ( Scalar :: from_bool ( res) , false , self . tcx . types . bool ) ;
8187 }
8288
8389 fn binary_float_op < F : Float + Into < Scalar < M :: PointerTag > > > (
8490 & self ,
8591 bin_op : mir:: BinOp ,
92+ ty : Ty < ' tcx > ,
8693 l : F ,
8794 r : F ,
88- ) -> ( Scalar < M :: PointerTag > , bool ) {
95+ ) -> ( Scalar < M :: PointerTag > , bool , Ty < ' tcx > ) {
8996 use rustc:: mir:: BinOp :: * ;
9097
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 ) ,
103110 _ => bug ! ( "invalid float op: `{:?}`" , bin_op) ,
104111 } ;
105- return ( val, false ) ;
112+ return ( val, false , ty ) ;
106113 }
107114
108115 fn binary_int_op (
@@ -113,7 +120,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
113120 left_layout : TyLayout < ' tcx > ,
114121 r : u128 ,
115122 right_layout : TyLayout < ' tcx > ,
116- ) -> InterpResult < ' tcx , ( Scalar < M :: PointerTag > , bool ) > {
123+ ) -> InterpResult < ' tcx , ( Scalar < M :: PointerTag > , bool , Ty < ' tcx > ) > {
117124 use rustc:: mir:: BinOp :: * ;
118125
119126 // 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> {
142149 }
143150 } ;
144151 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 ) ) ;
146153 }
147154
148155 // 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> {
167174 if let Some ( op) = op {
168175 let l = self . sign_extend ( l, left_layout) as i128 ;
169176 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 ) ) ;
171178 }
172179 let op: Option < fn ( i128 , i128 ) -> ( i128 , bool ) > = match bin_op {
173180 Div if r == 0 => throw_panic ! ( DivisionByZero ) ,
@@ -187,7 +194,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
187194 Rem | Div => {
188195 // int_min / -1
189196 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 ) ) ;
191198 }
192199 } ,
193200 _ => { } ,
@@ -202,25 +209,24 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
202209 // this may be out-of-bounds for the result type, so we have to truncate ourselves
203210 let result = result as u128 ;
204211 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 ) ) ;
206213 }
207214 }
208215
209216 let size = left_layout. size ;
210217
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 ) ,
215221
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 ) ,
220226
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 ) ,
224230
225231 Add | Sub | Mul | Rem | Div => {
226232 debug_assert ! ( !left_layout. abi. is_signed( ) ) ;
@@ -236,7 +242,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
236242 } ;
237243 let ( result, oflo) = op ( l, r) ;
238244 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+ ) ) ;
240250 }
241251
242252 _ => {
@@ -250,17 +260,17 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
250260 }
251261 } ;
252262
253- Ok ( ( val, false ) )
263+ Ok ( ( val, false , ty ) )
254264 }
255265
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 (
259269 & self ,
260270 bin_op : mir:: BinOp ,
261271 left : ImmTy < ' tcx , M :: PointerTag > ,
262272 right : ImmTy < ' tcx , M :: PointerTag > ,
263- ) -> InterpResult < ' tcx , ( Scalar < M :: PointerTag > , bool ) > {
273+ ) -> InterpResult < ' tcx , ( Scalar < M :: PointerTag > , bool , Ty < ' tcx > ) > {
264274 trace ! ( "Running binary op {:?}: {:?} ({:?}), {:?} ({:?})" ,
265275 bin_op, * left, left. layout. ty, * right, right. layout. ty) ;
266276
@@ -279,11 +289,14 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
279289 }
280290 ty:: Float ( fty) => {
281291 assert_eq ! ( left. layout. ty, right. layout. ty) ;
292+ let ty = left. layout . ty ;
282293 let left = left. to_scalar ( ) ?;
283294 let right = right. to_scalar ( ) ?;
284295 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 ( ) ?) ,
287300 } )
288301 }
289302 _ if left. layout . ty . is_integral ( ) => {
@@ -312,11 +325,23 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
312325 }
313326 }
314327
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+
315340 pub fn unary_op (
316341 & self ,
317342 un_op : mir:: UnOp ,
318343 val : ImmTy < ' tcx , M :: PointerTag > ,
319- ) -> InterpResult < ' tcx , Scalar < M :: PointerTag > > {
344+ ) -> InterpResult < ' tcx , ImmTy < ' tcx , M :: PointerTag > > {
320345 use rustc:: mir:: UnOp :: * ;
321346
322347 let layout = val. layout ;
@@ -330,15 +355,15 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
330355 Not => !val,
331356 _ => bug ! ( "Invalid bool op {:?}" , un_op)
332357 } ;
333- Ok ( Scalar :: from_bool ( res) )
358+ Ok ( ImmTy :: from_scalar ( Scalar :: from_bool ( res) , self . layout_of ( self . tcx . types . bool ) ? ) )
334359 }
335360 ty:: Float ( fty) => {
336361 let res = match ( un_op, fty) {
337362 ( Neg , FloatTy :: F32 ) => Scalar :: from_f32 ( -val. to_f32 ( ) ?) ,
338363 ( Neg , FloatTy :: F64 ) => Scalar :: from_f64 ( -val. to_f64 ( ) ?) ,
339364 _ => bug ! ( "Invalid float op {:?}" , un_op)
340365 } ;
341- Ok ( res)
366+ Ok ( ImmTy :: from_scalar ( res, layout ) )
342367 }
343368 _ => {
344369 assert ! ( layout. ty. is_integral( ) ) ;
@@ -351,7 +376,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
351376 }
352377 } ;
353378 // res needs tuncating
354- Ok ( Scalar :: from_uint ( self . truncate ( res, layout) , layout. size ) )
379+ Ok ( ImmTy :: from_uint ( self . truncate ( res, layout) , layout) )
355380 }
356381 }
357382 }
0 commit comments