1+ use std:: convert:: TryFrom ;
2+
13use rustc:: mir;
24use rustc:: mir:: interpret:: { InterpResult , Scalar } ;
35use rustc:: ty:: {
@@ -130,28 +132,27 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
130132 // Shift ops can have an RHS with a different numeric type.
131133 if bin_op == Shl || bin_op == Shr {
132134 let signed = left_layout. abi . is_signed ( ) ;
133- let mut oflo = ( r as u32 as u128 ) != r;
134- let mut r = r as u32 ;
135- let size = left_layout. size ;
136- oflo |= r >= size. bits ( ) as u32 ;
137- r %= size. bits ( ) as u32 ;
135+ let size = u128:: from ( left_layout. size . bits ( ) ) ;
136+ let overflow = r >= size;
137+ let r = r % size; // mask to type size
138+ let r = u32:: try_from ( r) . unwrap ( ) ; // we masked so this will always fit
138139 let result = if signed {
139140 let l = self . sign_extend ( l, left_layout) as i128 ;
140141 let result = match bin_op {
141- Shl => l << r ,
142- Shr => l >> r ,
142+ Shl => l. checked_shl ( r ) . unwrap ( ) ,
143+ Shr => l. checked_shr ( r ) . unwrap ( ) ,
143144 _ => bug ! ( "it has already been checked that this is a shift op" ) ,
144145 } ;
145146 result as u128
146147 } else {
147148 match bin_op {
148- Shl => l << r ,
149- Shr => l >> r ,
149+ Shl => l. checked_shl ( r ) . unwrap ( ) ,
150+ Shr => l. checked_shr ( r ) . unwrap ( ) ,
150151 _ => bug ! ( "it has already been checked that this is a shift op" ) ,
151152 }
152153 } ;
153154 let truncated = self . truncate ( result, left_layout) ;
154- return Ok ( ( Scalar :: from_uint ( truncated, size) , oflo , left_layout. ty ) ) ;
155+ return Ok ( ( Scalar :: from_uint ( truncated, left_layout . size ) , overflow , left_layout. ty ) ) ;
155156 }
156157
157158 // For the remaining ops, the types must be the same on both sides
@@ -193,7 +194,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
193194 _ => None ,
194195 } ;
195196 if let Some ( op) = op {
196- let l128 = self . sign_extend ( l, left_layout) as i128 ;
197197 let r = self . sign_extend ( r, right_layout) as i128 ;
198198 // We need a special check for overflowing remainder:
199199 // "int_min % -1" overflows and returns 0, but after casting things to a larger int
@@ -206,8 +206,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
206206 }
207207 _ => { }
208208 }
209+ let l = self . sign_extend ( l, left_layout) as i128 ;
209210
210- let ( result, oflo) = op ( l128 , r) ;
211+ let ( result, oflo) = op ( l , r) ;
211212 // This may be out-of-bounds for the result type, so we have to truncate ourselves.
212213 // If that truncation loses any information, we have an overflow.
213214 let result = result as u128 ;
0 commit comments