]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/hair/constant.rs
Rollup merge of #58627 - euclio:rustdoc-pass-order, r=QuietMisdreavus
[rust.git] / src / librustc_mir / hair / constant.rs
1 use syntax::ast;
2 use rustc::ty::{self, Ty, TyCtxt, ParamEnv};
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
12 crate fn lit_to_const<'a, 'gcx, 'tcx>(
13     lit: &'tcx ast::LitKind,
14     tcx: TyCtxt<'a, 'gcx, 'tcx>,
15     ty: Ty<'tcx>,
16     neg: bool,
17 ) -> Result<ty::Const<'tcx>, LitToConstError> {
18     use syntax::ast::*;
19
20     let trunc = |n| {
21         let param_ty = ParamEnv::reveal_all().and(tcx.lift_to_global(&ty).unwrap());
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());
24         let result = truncate(n, width);
25         trace!("trunc result: {}", result);
26         Ok(ConstValue::Scalar(Scalar::Bits {
27             bits: result,
28             size: width.bytes() as u8,
29         }))
30     };
31
32     use rustc::mir::interpret::*;
33     let lit = match *lit {
34         LitKind::Str(ref s, _) => {
35             let s = s.as_str();
36             let id = tcx.allocate_bytes(s.as_bytes());
37             ConstValue::new_slice(Scalar::Ptr(id.into()), s.len() as u64)
38         },
39         LitKind::Err(ref s) => {
40             let s = s.as_str();
41             let id = tcx.allocate_bytes(s.as_bytes());
42             return Ok(ty::Const {
43                 val: ConstValue::new_slice(Scalar::Ptr(id.into()), s.len() as u64),
44                 ty: tcx.types.err,
45             });
46         },
47         LitKind::ByteStr(ref data) => {
48             let id = tcx.allocate_bytes(data);
49             ConstValue::Scalar(Scalar::Ptr(id.into()))
50         },
51         LitKind::Byte(n) => ConstValue::Scalar(Scalar::Bits {
52             bits: n as u128,
53             size: 1,
54         }),
55         LitKind::Int(n, _) if neg => {
56             let n = n as i128;
57             let n = n.overflowing_neg().0;
58             trunc(n as u128)?
59         },
60         LitKind::Int(n, _) => trunc(n)?,
61         LitKind::Float(n, fty) => {
62             parse_float(n, fty, neg).map_err(|_| LitToConstError::UnparseableFloat)?
63         }
64         LitKind::FloatUnsuffixed(n) => {
65             let fty = match ty.sty {
66                 ty::Float(fty) => fty,
67                 _ => bug!()
68             };
69             parse_float(n, fty, neg).map_err(|_| LitToConstError::UnparseableFloat)?
70         }
71         LitKind::Bool(b) => ConstValue::Scalar(Scalar::from_bool(b)),
72         LitKind::Char(c) => ConstValue::Scalar(Scalar::from_char(c)),
73     };
74     Ok(ty::Const { val: lit, ty })
75 }
76
77 fn parse_float<'tcx>(
78     num: Symbol,
79     fty: ast::FloatTy,
80     neg: bool,
81 ) -> Result<ConstValue<'tcx>, ()> {
82     let num = num.as_str();
83     use rustc_apfloat::ieee::{Single, Double};
84     use rustc_apfloat::Float;
85     let (bits, size) = match fty {
86         ast::FloatTy::F32 => {
87             num.parse::<f32>().map_err(|_| ())?;
88             let mut f = num.parse::<Single>().unwrap_or_else(|e| {
89                 panic!("apfloat::ieee::Single failed to parse `{}`: {:?}", num, e)
90             });
91             if neg {
92                 f = -f;
93             }
94             (f.to_bits(), 4)
95         }
96         ast::FloatTy::F64 => {
97             num.parse::<f64>().map_err(|_| ())?;
98             let mut f = num.parse::<Double>().unwrap_or_else(|e| {
99                 panic!("apfloat::ieee::Single failed to parse `{}`: {:?}", num, e)
100             });
101             if neg {
102                 f = -f;
103             }
104             (f.to_bits(), 8)
105         }
106     };
107
108     Ok(ConstValue::Scalar(Scalar::Bits { bits, size }))
109 }