1
1
use rustc:: mir;
2
- use rustc:: ty:: Ty ;
2
+ use rustc:: ty:: { self , Ty } ;
3
3
4
4
use error:: { EvalError , EvalResult } ;
5
5
use eval_context:: EvalContext ;
@@ -25,11 +25,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
25
25
) -> EvalResult < ' tcx , ( PrimVal , bool ) > {
26
26
let left_ty = self . operand_ty ( left) ;
27
27
let right_ty = self . operand_ty ( right) ;
28
- let left_kind = self . ty_to_primval_kind ( left_ty) ?;
29
- let right_kind = self . ty_to_primval_kind ( right_ty) ?;
30
28
let left_val = self . eval_operand_to_primval ( left) ?;
31
29
let right_val = self . eval_operand_to_primval ( right) ?;
32
- binary_op ( op, left_val, left_kind , right_val, right_kind )
30
+ self . binary_op ( op, left_val, left_ty , right_val, right_ty )
33
31
}
34
32
35
33
/// Applies the binary operation `op` to the two operands and writes a tuple of the result
@@ -132,119 +130,141 @@ macro_rules! f64_arithmetic {
132
130
)
133
131
}
134
132
135
- /// Returns the result of the specified operation and whether it overflowed.
136
- pub fn binary_op < ' tcx > (
137
- bin_op : mir:: BinOp ,
138
- left : PrimVal ,
139
- left_kind : PrimValKind ,
140
- right : PrimVal ,
141
- right_kind : PrimValKind ,
142
- ) -> EvalResult < ' tcx , ( PrimVal , bool ) > {
143
- use rustc:: mir:: BinOp :: * ;
144
- use value:: PrimValKind :: * ;
145
-
146
- // FIXME(solson): Temporary hack. It will go away when we get rid of Pointer's ability to store
147
- // plain bytes, and leave that to PrimVal::Bytes.
148
- fn normalize ( val : PrimVal ) -> PrimVal {
149
- if let PrimVal :: Ptr ( ptr) = val {
150
- if let Ok ( bytes) = ptr. to_int ( ) {
151
- return PrimVal :: Bytes ( bytes as u128 ) ;
133
+ impl < ' a , ' tcx > EvalContext < ' a , ' tcx > {
134
+ /// Returns the result of the specified operation and whether it overflowed.
135
+ pub fn binary_op (
136
+ & self ,
137
+ bin_op : mir:: BinOp ,
138
+ left : PrimVal ,
139
+ left_ty : Ty < ' tcx > ,
140
+ right : PrimVal ,
141
+ right_ty : Ty < ' tcx > ,
142
+ ) -> EvalResult < ' tcx , ( PrimVal , bool ) > {
143
+ use rustc:: mir:: BinOp :: * ;
144
+ use value:: PrimValKind :: * ;
145
+
146
+ // FIXME(solson): Temporary hack. It will go away when we get rid of Pointer's ability to store
147
+ // plain bytes, and leave that to PrimVal::Bytes.
148
+ fn normalize ( val : PrimVal ) -> PrimVal {
149
+ if let PrimVal :: Ptr ( ptr) = val {
150
+ if let Ok ( bytes) = ptr. to_int ( ) {
151
+ return PrimVal :: Bytes ( bytes as u128 ) ;
152
+ }
152
153
}
154
+ val
153
155
}
154
- val
155
- }
156
- let ( left, right) = ( normalize ( left) , normalize ( right) ) ;
156
+ let ( left, right) = ( normalize ( left) , normalize ( right) ) ;
157
157
158
- let ( l, r) = match ( left, right) {
159
- ( PrimVal :: Bytes ( left_bytes) , PrimVal :: Bytes ( right_bytes) ) => ( left_bytes, right_bytes) ,
160
-
161
- ( PrimVal :: Ptr ( left_ptr) , PrimVal :: Ptr ( right_ptr) ) => {
162
- if left_ptr. alloc_id == right_ptr. alloc_id {
163
- // If the pointers are into the same allocation, fall through to the more general
164
- // match later, which will do comparisons on the pointer offsets.
165
- ( left_ptr. offset as u128 , right_ptr. offset as u128 )
166
- } else {
167
- return Ok ( ( unrelated_ptr_ops ( bin_op, left_ptr, right_ptr) ?, false ) ) ;
168
- }
158
+ // Offset is handled early, before we dispatch to unrelated_ptr_ops. We have to also catch the case where both arguments *are* convertible to integers.
159
+ if bin_op == Offset {
160
+ let pointee_ty = left_ty. builtin_deref ( true , ty:: LvaluePreference :: NoPreference ) . expect ( "Offset called on non-ptr type" ) . ty ;
161
+ let ptr = self . pointer_offset ( left. to_ptr ( ) ?, pointee_ty, right. to_bytes ( ) ? as i64 ) ?;
162
+ return Ok ( ( PrimVal :: Ptr ( ptr) , false ) ) ;
169
163
}
170
164
171
- ( PrimVal :: Ptr ( ptr) , PrimVal :: Bytes ( bytes) ) |
172
- ( PrimVal :: Bytes ( bytes) , PrimVal :: Ptr ( ptr) ) => {
173
- return Ok ( ( unrelated_ptr_ops ( bin_op, ptr, Pointer :: from_int ( bytes as u64 ) ) ?, false ) ) ;
174
- }
165
+ let ( l, r) = match ( left, right) {
166
+ ( PrimVal :: Bytes ( left_bytes) , PrimVal :: Bytes ( right_bytes) ) => ( left_bytes, right_bytes) ,
167
+
168
+ ( PrimVal :: Ptr ( left_ptr) , PrimVal :: Ptr ( right_ptr) ) => {
169
+ if left_ptr. alloc_id == right_ptr. alloc_id {
170
+ // If the pointers are into the same allocation, fall through to the more general
171
+ // match later, which will do comparisons on the pointer offsets.
172
+ ( left_ptr. offset as u128 , right_ptr. offset as u128 )
173
+ } else {
174
+ return Ok ( ( unrelated_ptr_ops ( bin_op, left_ptr, right_ptr) ?, false ) ) ;
175
+ }
176
+ }
175
177
176
- ( PrimVal :: Undef , _) | ( _, PrimVal :: Undef ) => return Err ( EvalError :: ReadUndefBytes ) ,
177
- } ;
178
+ ( PrimVal :: Ptr ( ptr) , PrimVal :: Bytes ( bytes) ) |
179
+ ( PrimVal :: Bytes ( bytes) , PrimVal :: Ptr ( ptr) ) => {
180
+ return Ok ( ( unrelated_ptr_ops ( bin_op, ptr, Pointer :: from_int ( bytes as u64 ) ) ?, false ) ) ;
181
+ }
178
182
179
- // These ops can have an RHS with a different numeric type.
180
- if bin_op == Shl || bin_op == Shr {
181
- return match bin_op {
182
- Shl => int_shift ! ( left_kind, overflowing_shl, l, r as u32 ) ,
183
- Shr => int_shift ! ( left_kind, overflowing_shr, l, r as u32 ) ,
184
- _ => bug ! ( "it has already been checked that this is a shift op" ) ,
183
+ ( PrimVal :: Undef , _) | ( _, PrimVal :: Undef ) => return Err ( EvalError :: ReadUndefBytes ) ,
185
184
} ;
186
- }
187
185
188
- if left_kind != right_kind {
189
- let msg = format ! ( "unimplemented binary op: {:?}, {:?}, {:?}" , left, right, bin_op) ;
190
- return Err ( EvalError :: Unimplemented ( msg) ) ;
191
- }
186
+ let left_kind = self . ty_to_primval_kind ( left_ty) ?;
187
+ let right_kind = self . ty_to_primval_kind ( right_ty) ?;
192
188
193
- let val = match ( bin_op, left_kind) {
194
- ( Eq , F32 ) => PrimVal :: from_bool ( bytes_to_f32 ( l) == bytes_to_f32 ( r) ) ,
195
- ( Ne , F32 ) => PrimVal :: from_bool ( bytes_to_f32 ( l) != bytes_to_f32 ( r) ) ,
196
- ( Lt , F32 ) => PrimVal :: from_bool ( bytes_to_f32 ( l) < bytes_to_f32 ( r) ) ,
197
- ( Le , F32 ) => PrimVal :: from_bool ( bytes_to_f32 ( l) <= bytes_to_f32 ( r) ) ,
198
- ( Gt , F32 ) => PrimVal :: from_bool ( bytes_to_f32 ( l) > bytes_to_f32 ( r) ) ,
199
- ( Ge , F32 ) => PrimVal :: from_bool ( bytes_to_f32 ( l) >= bytes_to_f32 ( r) ) ,
200
-
201
- ( Eq , F64 ) => PrimVal :: from_bool ( bytes_to_f64 ( l) == bytes_to_f64 ( r) ) ,
202
- ( Ne , F64 ) => PrimVal :: from_bool ( bytes_to_f64 ( l) != bytes_to_f64 ( r) ) ,
203
- ( Lt , F64 ) => PrimVal :: from_bool ( bytes_to_f64 ( l) < bytes_to_f64 ( r) ) ,
204
- ( Le , F64 ) => PrimVal :: from_bool ( bytes_to_f64 ( l) <= bytes_to_f64 ( r) ) ,
205
- ( Gt , F64 ) => PrimVal :: from_bool ( bytes_to_f64 ( l) > bytes_to_f64 ( r) ) ,
206
- ( Ge , F64 ) => PrimVal :: from_bool ( bytes_to_f64 ( l) >= bytes_to_f64 ( r) ) ,
207
-
208
- ( Add , F32 ) => f32_arithmetic ! ( +, l, r) ,
209
- ( Sub , F32 ) => f32_arithmetic ! ( -, l, r) ,
210
- ( Mul , F32 ) => f32_arithmetic ! ( * , l, r) ,
211
- ( Div , F32 ) => f32_arithmetic ! ( /, l, r) ,
212
- ( Rem , F32 ) => f32_arithmetic ! ( %, l, r) ,
213
-
214
- ( Add , F64 ) => f64_arithmetic ! ( +, l, r) ,
215
- ( Sub , F64 ) => f64_arithmetic ! ( -, l, r) ,
216
- ( Mul , F64 ) => f64_arithmetic ! ( * , l, r) ,
217
- ( Div , F64 ) => f64_arithmetic ! ( /, l, r) ,
218
- ( Rem , F64 ) => f64_arithmetic ! ( %, l, r) ,
219
-
220
- ( Eq , _) => PrimVal :: from_bool ( l == r) ,
221
- ( Ne , _) => PrimVal :: from_bool ( l != r) ,
222
- ( Lt , k) if k. is_signed_int ( ) => PrimVal :: from_bool ( ( l as i128 ) < ( r as i128 ) ) ,
223
- ( Lt , _) => PrimVal :: from_bool ( l < r) ,
224
- ( Le , k) if k. is_signed_int ( ) => PrimVal :: from_bool ( ( l as i128 ) <= ( r as i128 ) ) ,
225
- ( Le , _) => PrimVal :: from_bool ( l <= r) ,
226
- ( Gt , k) if k. is_signed_int ( ) => PrimVal :: from_bool ( ( l as i128 ) > ( r as i128 ) ) ,
227
- ( Gt , _) => PrimVal :: from_bool ( l > r) ,
228
- ( Ge , k) if k. is_signed_int ( ) => PrimVal :: from_bool ( ( l as i128 ) >= ( r as i128 ) ) ,
229
- ( Ge , _) => PrimVal :: from_bool ( l >= r) ,
230
-
231
- ( BitOr , _) => PrimVal :: Bytes ( l | r) ,
232
- ( BitAnd , _) => PrimVal :: Bytes ( l & r) ,
233
- ( BitXor , _) => PrimVal :: Bytes ( l ^ r) ,
234
-
235
- ( Add , k) if k. is_int ( ) => return int_arithmetic ! ( k, overflowing_add, l, r) ,
236
- ( Sub , k) if k. is_int ( ) => return int_arithmetic ! ( k, overflowing_sub, l, r) ,
237
- ( Mul , k) if k. is_int ( ) => return int_arithmetic ! ( k, overflowing_mul, l, r) ,
238
- ( Div , k) if k. is_int ( ) => return int_arithmetic ! ( k, overflowing_div, l, r) ,
239
- ( Rem , k) if k. is_int ( ) => return int_arithmetic ! ( k, overflowing_rem, l, r) ,
189
+ // These ops can have an RHS with a different numeric type.
190
+ if bin_op == Shl || bin_op == Shr {
191
+ return match bin_op {
192
+ Shl => int_shift ! ( left_kind, overflowing_shl, l, r as u32 ) ,
193
+ Shr => int_shift ! ( left_kind, overflowing_shr, l, r as u32 ) ,
194
+ _ => bug ! ( "it has already been checked that this is a shift op" ) ,
195
+ } ;
196
+ }
197
+ if bin_op == Offset {
198
+ // We permit offset-by-0 in any case. Drop glue actually does this, and it's probably (TM) fine for LLVM.
199
+ if left_kind == PrimValKind :: Ptr && right_kind. is_int ( ) && r == 0 {
200
+ return Ok ( ( PrimVal :: Bytes ( l) , false ) ) ;
201
+ } else {
202
+ let msg = format ! ( "unimplemented Offset: {:?}, {:?}" , left, right) ;
203
+ return Err ( EvalError :: Unimplemented ( msg) ) ;
204
+ }
205
+ }
240
206
241
- _ => {
207
+ if left_kind != right_kind {
242
208
let msg = format ! ( "unimplemented binary op: {:?}, {:?}, {:?}" , left, right, bin_op) ;
243
209
return Err ( EvalError :: Unimplemented ( msg) ) ;
244
210
}
245
- } ;
246
211
247
- Ok ( ( val, false ) )
212
+ let val = match ( bin_op, left_kind) {
213
+ ( Eq , F32 ) => PrimVal :: from_bool ( bytes_to_f32 ( l) == bytes_to_f32 ( r) ) ,
214
+ ( Ne , F32 ) => PrimVal :: from_bool ( bytes_to_f32 ( l) != bytes_to_f32 ( r) ) ,
215
+ ( Lt , F32 ) => PrimVal :: from_bool ( bytes_to_f32 ( l) < bytes_to_f32 ( r) ) ,
216
+ ( Le , F32 ) => PrimVal :: from_bool ( bytes_to_f32 ( l) <= bytes_to_f32 ( r) ) ,
217
+ ( Gt , F32 ) => PrimVal :: from_bool ( bytes_to_f32 ( l) > bytes_to_f32 ( r) ) ,
218
+ ( Ge , F32 ) => PrimVal :: from_bool ( bytes_to_f32 ( l) >= bytes_to_f32 ( r) ) ,
219
+
220
+ ( Eq , F64 ) => PrimVal :: from_bool ( bytes_to_f64 ( l) == bytes_to_f64 ( r) ) ,
221
+ ( Ne , F64 ) => PrimVal :: from_bool ( bytes_to_f64 ( l) != bytes_to_f64 ( r) ) ,
222
+ ( Lt , F64 ) => PrimVal :: from_bool ( bytes_to_f64 ( l) < bytes_to_f64 ( r) ) ,
223
+ ( Le , F64 ) => PrimVal :: from_bool ( bytes_to_f64 ( l) <= bytes_to_f64 ( r) ) ,
224
+ ( Gt , F64 ) => PrimVal :: from_bool ( bytes_to_f64 ( l) > bytes_to_f64 ( r) ) ,
225
+ ( Ge , F64 ) => PrimVal :: from_bool ( bytes_to_f64 ( l) >= bytes_to_f64 ( r) ) ,
226
+
227
+ ( Add , F32 ) => f32_arithmetic ! ( +, l, r) ,
228
+ ( Sub , F32 ) => f32_arithmetic ! ( -, l, r) ,
229
+ ( Mul , F32 ) => f32_arithmetic ! ( * , l, r) ,
230
+ ( Div , F32 ) => f32_arithmetic ! ( /, l, r) ,
231
+ ( Rem , F32 ) => f32_arithmetic ! ( %, l, r) ,
232
+
233
+ ( Add , F64 ) => f64_arithmetic ! ( +, l, r) ,
234
+ ( Sub , F64 ) => f64_arithmetic ! ( -, l, r) ,
235
+ ( Mul , F64 ) => f64_arithmetic ! ( * , l, r) ,
236
+ ( Div , F64 ) => f64_arithmetic ! ( /, l, r) ,
237
+ ( Rem , F64 ) => f64_arithmetic ! ( %, l, r) ,
238
+
239
+ ( Eq , _) => PrimVal :: from_bool ( l == r) ,
240
+ ( Ne , _) => PrimVal :: from_bool ( l != r) ,
241
+ ( Lt , k) if k. is_signed_int ( ) => PrimVal :: from_bool ( ( l as i128 ) < ( r as i128 ) ) ,
242
+ ( Lt , _) => PrimVal :: from_bool ( l < r) ,
243
+ ( Le , k) if k. is_signed_int ( ) => PrimVal :: from_bool ( ( l as i128 ) <= ( r as i128 ) ) ,
244
+ ( Le , _) => PrimVal :: from_bool ( l <= r) ,
245
+ ( Gt , k) if k. is_signed_int ( ) => PrimVal :: from_bool ( ( l as i128 ) > ( r as i128 ) ) ,
246
+ ( Gt , _) => PrimVal :: from_bool ( l > r) ,
247
+ ( Ge , k) if k. is_signed_int ( ) => PrimVal :: from_bool ( ( l as i128 ) >= ( r as i128 ) ) ,
248
+ ( Ge , _) => PrimVal :: from_bool ( l >= r) ,
249
+
250
+ ( BitOr , _) => PrimVal :: Bytes ( l | r) ,
251
+ ( BitAnd , _) => PrimVal :: Bytes ( l & r) ,
252
+ ( BitXor , _) => PrimVal :: Bytes ( l ^ r) ,
253
+
254
+ ( Add , k) if k. is_int ( ) => return int_arithmetic ! ( k, overflowing_add, l, r) ,
255
+ ( Sub , k) if k. is_int ( ) => return int_arithmetic ! ( k, overflowing_sub, l, r) ,
256
+ ( Mul , k) if k. is_int ( ) => return int_arithmetic ! ( k, overflowing_mul, l, r) ,
257
+ ( Div , k) if k. is_int ( ) => return int_arithmetic ! ( k, overflowing_div, l, r) ,
258
+ ( Rem , k) if k. is_int ( ) => return int_arithmetic ! ( k, overflowing_rem, l, r) ,
259
+
260
+ _ => {
261
+ let msg = format ! ( "unimplemented binary op: {:?}, {:?}, {:?}" , left, right, bin_op) ;
262
+ return Err ( EvalError :: Unimplemented ( msg) ) ;
263
+ }
264
+ } ;
265
+
266
+ Ok ( ( val, false ) )
267
+ }
248
268
}
249
269
250
270
fn unrelated_ptr_ops < ' tcx > ( bin_op : mir:: BinOp , left : Pointer , right : Pointer ) -> EvalResult < ' tcx , PrimVal > {
0 commit comments