]>
Commit | Line | Data |
---|---|---|
a1dfa0c6 | 1 | use syntax::ast; |
dc9dc135 | 2 | use rustc::ty::{self, Ty, TyCtxt, ParamEnv, layout::Size}; |
a1dfa0c6 XL |
3 | use syntax_pos::symbol::Symbol; |
4 | use rustc::mir::interpret::{ConstValue, Scalar}; | |
5 | ||
6 | #[derive(PartialEq)] | |
7 | crate enum LitToConstError { | |
8 | UnparseableFloat, | |
9 | Reported, | |
10 | } | |
11 | ||
dc9dc135 | 12 | crate fn lit_to_const<'tcx>( |
a1dfa0c6 | 13 | lit: &'tcx ast::LitKind, |
dc9dc135 | 14 | tcx: TyCtxt<'tcx>, |
a1dfa0c6 XL |
15 | ty: Ty<'tcx>, |
16 | neg: bool, | |
dc9dc135 | 17 | ) -> Result<&'tcx ty::Const<'tcx>, LitToConstError> { |
a1dfa0c6 XL |
18 | use syntax::ast::*; |
19 | ||
20 | let trunc = |n| { | |
dc9dc135 | 21 | let param_ty = ParamEnv::reveal_all().and(ty); |
a1dfa0c6 XL |
22 | let width = tcx.layout_of(param_ty).map_err(|_| LitToConstError::Reported)?.size; |
23 | trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits()); | |
9fa01778 | 24 | let result = truncate(n, width); |
a1dfa0c6 | 25 | trace!("trunc result: {}", result); |
dc9dc135 | 26 | Ok(ConstValue::Scalar(Scalar::from_uint(result, width))) |
a1dfa0c6 XL |
27 | }; |
28 | ||
29 | use rustc::mir::interpret::*; | |
30 | let lit = match *lit { | |
31 | LitKind::Str(ref s, _) => { | |
32 | let s = s.as_str(); | |
dc9dc135 XL |
33 | let allocation = Allocation::from_byte_aligned_bytes(s.as_bytes()); |
34 | let allocation = tcx.intern_const_alloc(allocation); | |
35 | ConstValue::Slice { data: allocation, start: 0, end: s.len() } | |
a1dfa0c6 XL |
36 | }, |
37 | LitKind::ByteStr(ref data) => { | |
38 | let id = tcx.allocate_bytes(data); | |
39 | ConstValue::Scalar(Scalar::Ptr(id.into())) | |
40 | }, | |
dc9dc135 | 41 | LitKind::Byte(n) => ConstValue::Scalar(Scalar::from_uint(n, Size::from_bytes(1))), |
a1dfa0c6 XL |
42 | LitKind::Int(n, _) if neg => { |
43 | let n = n as i128; | |
44 | let n = n.overflowing_neg().0; | |
45 | trunc(n as u128)? | |
46 | }, | |
47 | LitKind::Int(n, _) => trunc(n)?, | |
60c5eb7d | 48 | LitKind::Float(n, _) => { |
e74abb32 | 49 | let fty = match ty.kind { |
a1dfa0c6 XL |
50 | ty::Float(fty) => fty, |
51 | _ => bug!() | |
52 | }; | |
53 | parse_float(n, fty, neg).map_err(|_| LitToConstError::UnparseableFloat)? | |
54 | } | |
55 | LitKind::Bool(b) => ConstValue::Scalar(Scalar::from_bool(b)), | |
56 | LitKind::Char(c) => ConstValue::Scalar(Scalar::from_char(c)), | |
dc9dc135 | 57 | LitKind::Err(_) => unreachable!(), |
a1dfa0c6 | 58 | }; |
60c5eb7d | 59 | Ok(tcx.mk_const(ty::Const { val: ty::ConstKind::Value(lit), ty })) |
a1dfa0c6 XL |
60 | } |
61 | ||
62 | fn parse_float<'tcx>( | |
63 | num: Symbol, | |
64 | fty: ast::FloatTy, | |
65 | neg: bool, | |
66 | ) -> Result<ConstValue<'tcx>, ()> { | |
67 | let num = num.as_str(); | |
68 | use rustc_apfloat::ieee::{Single, Double}; | |
dc9dc135 | 69 | let scalar = match fty { |
a1dfa0c6 XL |
70 | ast::FloatTy::F32 => { |
71 | num.parse::<f32>().map_err(|_| ())?; | |
72 | let mut f = num.parse::<Single>().unwrap_or_else(|e| { | |
73 | panic!("apfloat::ieee::Single failed to parse `{}`: {:?}", num, e) | |
74 | }); | |
75 | if neg { | |
76 | f = -f; | |
77 | } | |
dc9dc135 | 78 | Scalar::from_f32(f) |
a1dfa0c6 XL |
79 | } |
80 | ast::FloatTy::F64 => { | |
81 | num.parse::<f64>().map_err(|_| ())?; | |
82 | let mut f = num.parse::<Double>().unwrap_or_else(|e| { | |
dc9dc135 | 83 | panic!("apfloat::ieee::Double failed to parse `{}`: {:?}", num, e) |
a1dfa0c6 XL |
84 | }); |
85 | if neg { | |
86 | f = -f; | |
87 | } | |
dc9dc135 | 88 | Scalar::from_f64(f) |
a1dfa0c6 XL |
89 | } |
90 | }; | |
91 | ||
dc9dc135 | 92 | Ok(ConstValue::Scalar(scalar)) |
a1dfa0c6 | 93 | } |