]> git.lizzy.rs Git - rust.git/blob - src/primval.rs
forbid calling functions through pointers of a different type
[rust.git] / src / primval.rs
1 use rustc::mir::repr as mir;
2
3 use error::{EvalError, EvalResult};
4 use memory::Pointer;
5
6 #[derive(Clone, Copy, Debug, PartialEq)]
7 pub enum PrimVal {
8     Bool(bool),
9     I8(i8), I16(i16), I32(i32), I64(i64),
10     U8(u8), U16(u16), U32(u32), U64(u64),
11
12     AbstractPtr(Pointer),
13     IntegerPtr(u64),
14 }
15
16 pub fn binary_op<'tcx>(bin_op: mir::BinOp, left: PrimVal, right: PrimVal) -> EvalResult<'tcx, PrimVal> {
17     use rustc::mir::repr::BinOp::*;
18     use self::PrimVal::*;
19
20     macro_rules! int_binops {
21         ($v:ident, $l:ident, $r:ident) => ({
22             match bin_op {
23                 Add    => $v($l + $r),
24                 Sub    => $v($l - $r),
25                 Mul    => $v($l * $r),
26                 Div    => $v($l / $r),
27                 Rem    => $v($l % $r),
28                 BitXor => $v($l ^ $r),
29                 BitAnd => $v($l & $r),
30                 BitOr  => $v($l | $r),
31
32                 // TODO(solson): Can have differently-typed RHS.
33                 Shl => $v($l << $r),
34                 Shr => $v($l >> $r),
35
36                 Eq => Bool($l == $r),
37                 Ne => Bool($l != $r),
38                 Lt => Bool($l < $r),
39                 Le => Bool($l <= $r),
40                 Gt => Bool($l > $r),
41                 Ge => Bool($l >= $r),
42             }
43         })
44     }
45
46     fn unrelated_ptr_ops<'tcx>(bin_op: mir::BinOp) -> EvalResult<'tcx, PrimVal> {
47         use rustc::mir::repr::BinOp::*;
48         match bin_op {
49             Eq => Ok(Bool(false)),
50             Ne => Ok(Bool(true)),
51             Lt | Le | Gt | Ge => Err(EvalError::InvalidPointerMath),
52             _ => unimplemented!(),
53         }
54     }
55
56     let val = match (left, right) {
57         (I8(l),  I8(r))  => int_binops!(I8, l, r),
58         (I16(l), I16(r)) => int_binops!(I16, l, r),
59         (I32(l), I32(r)) => int_binops!(I32, l, r),
60         (I64(l), I64(r)) => int_binops!(I64, l, r),
61         (U8(l),  U8(r))  => int_binops!(U8, l, r),
62         (U16(l), U16(r)) => int_binops!(U16, l, r),
63         (U32(l), U32(r)) => int_binops!(U32, l, r),
64         (U64(l), U64(r)) => int_binops!(U64, l, r),
65
66         (Bool(l), Bool(r)) => {
67             Bool(match bin_op {
68                 Eq => l == r,
69                 Ne => l != r,
70                 Lt => l < r,
71                 Le => l <= r,
72                 Gt => l > r,
73                 Ge => l >= r,
74                 BitOr => l | r,
75                 BitXor => l ^ r,
76                 BitAnd => l & r,
77                 Add | Sub | Mul | Div | Rem | Shl | Shr => return Err(EvalError::InvalidBoolOp(bin_op)),
78             })
79         }
80
81         (IntegerPtr(l), IntegerPtr(r)) => int_binops!(IntegerPtr, l, r),
82
83         (AbstractPtr(_), IntegerPtr(_)) | (IntegerPtr(_), AbstractPtr(_)) =>
84             return unrelated_ptr_ops(bin_op),
85
86         (AbstractPtr(l_ptr), AbstractPtr(r_ptr)) => {
87             if l_ptr.alloc_id != r_ptr.alloc_id {
88                 return unrelated_ptr_ops(bin_op);
89             }
90
91             let l = l_ptr.offset;
92             let r = r_ptr.offset;
93
94             match bin_op {
95                 Eq => Bool(l == r),
96                 Ne => Bool(l != r),
97                 Lt => Bool(l < r),
98                 Le => Bool(l <= r),
99                 Gt => Bool(l > r),
100                 Ge => Bool(l >= r),
101                 _ => return Err(EvalError::Unimplemented(format!("unimplemented ptr op: {:?}", bin_op))),
102             }
103         }
104
105         (l, r) => return Err(EvalError::Unimplemented(format!("unimplemented binary op: {:?}, {:?}, {:?}", l, r, bin_op))),
106     };
107
108     Ok(val)
109 }
110
111 pub fn unary_op<'tcx>(un_op: mir::UnOp, val: PrimVal) -> EvalResult<'tcx, PrimVal> {
112     use rustc::mir::repr::UnOp::*;
113     use self::PrimVal::*;
114     match (un_op, val) {
115         (Not, Bool(b)) => Ok(Bool(!b)),
116         (Not, I8(n))  => Ok(I8(!n)),
117         (Neg, I8(n))  => Ok(I8(-n)),
118         (Not, I16(n)) => Ok(I16(!n)),
119         (Neg, I16(n)) => Ok(I16(-n)),
120         (Not, I32(n)) => Ok(I32(!n)),
121         (Neg, I32(n)) => Ok(I32(-n)),
122         (Not, I64(n)) => Ok(I64(!n)),
123         (Neg, I64(n)) => Ok(I64(-n)),
124         (Not, U8(n))  => Ok(U8(!n)),
125         (Not, U16(n)) => Ok(U16(!n)),
126         (Not, U32(n)) => Ok(U32(!n)),
127         (Not, U64(n)) => Ok(U64(!n)),
128         _ => Err(EvalError::Unimplemented(format!("unimplemented unary op: {:?}, {:?}", un_op, val))),
129     }
130 }