]> git.lizzy.rs Git - rust.git/commitdiff
Deduplicate literal -> constant lowering
authorOliver Scherer <github35764891676564198441@oli-obk.de>
Wed, 28 Nov 2018 15:07:30 +0000 (16:07 +0100)
committerOliver Scherer <github35764891676564198441@oli-obk.de>
Wed, 28 Nov 2018 15:07:30 +0000 (16:07 +0100)
src/librustc_mir/hair/cx/mod.rs
src/librustc_mir/hair/pattern/mod.rs

index 733580b3ce2fd4acfd8c7beb64807012651724e4..ea1ec24c9914179d22015f5c505c45821a5a88a2 100644 (file)
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::subst::{Kind, Substs};
 use rustc::ty::layout::VariantIdx;
-use syntax::ast::{self, LitKind};
+use syntax::ast;
 use syntax::attr;
 use syntax::symbol::Symbol;
 use rustc::hir;
 use rustc_data_structures::sync::Lrc;
-use hair::pattern::parse_float;
+use hair::pattern::{lit_to_const, LitToConstError};
 
 #[derive(Clone)]
 pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
@@ -131,7 +131,6 @@ pub fn false_literal(&mut self) -> &'tcx ty::Const<'tcx> {
         ty::Const::from_bool(self.tcx, false)
     }
 
-    // FIXME: Combine with rustc_mir::hair::pattern::lit_to_const
     pub fn const_eval_literal(
         &mut self,
         lit: &'tcx ast::LitKind,
@@ -141,61 +140,19 @@ pub fn const_eval_literal(
     ) -> &'tcx ty::Const<'tcx> {
         trace!("const_eval_literal: {:#?}, {:?}, {:?}, {:?}", lit, ty, sp, neg);
 
-        let parse_float = |num, fty| -> ConstValue<'tcx> {
-            parse_float(num, fty, neg).unwrap_or_else(|_| {
+        match lit_to_const(lit, self.tcx, ty, neg) {
+            Ok(c) => c,
+            Err(LitToConstError::UnparseableFloat) => {
                 // FIXME(#31407) this is only necessary because float parsing is buggy
-                self.tcx.sess.span_fatal(sp, "could not evaluate float literal (see issue #31407)");
-            })
-        };
-
-        let trunc = |n| {
-            let param_ty = self.param_env.and(self.tcx.lift_to_global(&ty).unwrap());
-            let width = self.tcx.layout_of(param_ty).unwrap().size;
-            trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
-            let shift = 128 - width.bits();
-            let result = (n << shift) >> shift;
-            trace!("trunc result: {}", result);
-            ConstValue::Scalar(Scalar::Bits {
-                bits: result,
-                size: width.bytes() as u8,
-            })
-        };
-
-        use rustc::mir::interpret::*;
-        let lit = match *lit {
-            LitKind::Str(ref s, _) => {
-                let s = s.as_str();
-                let id = self.tcx.allocate_bytes(s.as_bytes());
-                ConstValue::new_slice(Scalar::Ptr(id.into()), s.len() as u64, &self.tcx)
-            },
-            LitKind::ByteStr(ref data) => {
-                let id = self.tcx.allocate_bytes(data);
-                ConstValue::Scalar(Scalar::Ptr(id.into()))
+                self.tcx.sess.span_err(sp, "could not evaluate float literal (see issue #31407)");
+                // create a dummy value and continue compiling
+                Const::from_bits(self.tcx, 0, self.param_env.and(ty))
             },
-            LitKind::Byte(n) => ConstValue::Scalar(Scalar::Bits {
-                bits: n as u128,
-                size: 1,
-            }),
-            LitKind::Int(n, _) if neg => {
-                let n = n as i128;
-                let n = n.overflowing_neg().0;
-                trunc(n as u128)
-            },
-            LitKind::Int(n, _) => trunc(n),
-            LitKind::Float(n, fty) => {
-                parse_float(n, fty)
-            }
-            LitKind::FloatUnsuffixed(n) => {
-                let fty = match ty.sty {
-                    ty::Float(fty) => fty,
-                    _ => bug!()
-                };
-                parse_float(n, fty)
+            Err(LitToConstError::Reported) => {
+                // create a dummy value and continue compiling
+                Const::from_bits(self.tcx, 0, self.param_env.and(ty))
             }
-            LitKind::Bool(b) => ConstValue::Scalar(Scalar::from_bool(b)),
-            LitKind::Char(c) => ConstValue::Scalar(Scalar::from_char(c)),
-        };
-        ty::Const::from_const_value(self.tcx, lit, ty)
+        }
     }
 
     pub fn pattern_from_hir(&mut self, p: &hir::Pat) -> Pattern<'tcx> {
index 941744c0aab7cc285c1e8bfd5a8173fede1933f5..deea03acf0c21cf9f8397f9e4951dbdb7b454ccd 100644 (file)
@@ -23,7 +23,7 @@
 use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability};
 use rustc::mir::{ProjectionElem, UserTypeAnnotation, UserTypeProjection, UserTypeProjections};
 use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend};
-use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty};
+use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty, ParamEnv};
 use rustc::ty::subst::{Substs, Kind};
 use rustc::ty::layout::VariantIdx;
 use rustc::hir::{self, PatKind, RangeEnd};
@@ -891,12 +891,11 @@ fn lower_lit(&mut self, expr: &'tcx hir::Expr) -> PatternKind<'tcx> {
                         );
                         *self.const_to_pat(instance, val, expr.hir_id, lit.span).kind
                     },
-                    Err(e) => {
-                        if e == LitToConstError::UnparseableFloat {
-                            self.errors.push(PatternError::FloatBug);
-                        }
+                    Err(LitToConstError::UnparseableFloat) => {
+                        self.errors.push(PatternError::FloatBug);
                         PatternKind::Wild
                     },
+                    Err(LitToConstError::Reported) => PatternKind::Wild,
                 }
             },
             hir::ExprKind::Path(ref qpath) => *self.lower_path(qpath, expr.hir_id, expr.span).kind,
@@ -914,12 +913,11 @@ fn lower_lit(&mut self, expr: &'tcx hir::Expr) -> PatternKind<'tcx> {
                         );
                         *self.const_to_pat(instance, val, expr.hir_id, lit.span).kind
                     },
-                    Err(e) => {
-                        if e == LitToConstError::UnparseableFloat {
-                            self.errors.push(PatternError::FloatBug);
-                        }
+                    Err(LitToConstError::UnparseableFloat) => {
+                        self.errors.push(PatternError::FloatBug);
                         PatternKind::Wild
                     },
+                    Err(LitToConstError::Reported) => PatternKind::Wild,
                 }
             }
             _ => span_bug!(expr.span, "not a literal: {:?}", expr),
@@ -1296,19 +1294,32 @@ pub fn compare_const_vals<'a, 'tcx>(
 }
 
 #[derive(PartialEq)]
-enum LitToConstError {
+pub enum LitToConstError {
     UnparseableFloat,
-    Propagated,
+    Reported,
 }
 
-// FIXME: Combine with rustc_mir::hair::cx::const_eval_literal
-fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
-                          tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                          ty: Ty<'tcx>,
-                          neg: bool)
-                          -> Result<&'tcx ty::Const<'tcx>, LitToConstError> {
+pub fn lit_to_const<'a, 'gcx, 'tcx>(
+    lit: &'tcx ast::LitKind,
+    tcx: TyCtxt<'a, 'gcx, 'tcx>,
+    ty: Ty<'tcx>,
+    neg: bool,
+) -> Result<&'tcx ty::Const<'tcx>, LitToConstError> {
     use syntax::ast::*;
 
+    let trunc = |n| {
+        let param_ty = ParamEnv::reveal_all().and(tcx.lift_to_global(&ty).unwrap());
+        let width = tcx.layout_of(param_ty).map_err(|_| LitToConstError::Reported)?.size;
+        trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
+        let shift = 128 - width.bits();
+        let result = (n << shift) >> shift;
+        trace!("trunc result: {}", result);
+        Ok(ConstValue::Scalar(Scalar::Bits {
+            bits: result,
+            size: width.bytes() as u8,
+        }))
+    };
+
     use rustc::mir::interpret::*;
     let lit = match *lit {
         LitKind::Str(ref s, _) => {
@@ -1324,48 +1335,12 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
             bits: n as u128,
             size: 1,
         }),
-        LitKind::Int(n, _) => {
-            enum Int {
-                Signed(IntTy),
-                Unsigned(UintTy),
-            }
-            let ity = match ty.sty {
-                ty::Int(IntTy::Isize) => Int::Signed(tcx.sess.target.isize_ty),
-                ty::Int(other) => Int::Signed(other),
-                ty::Uint(UintTy::Usize) => Int::Unsigned(tcx.sess.target.usize_ty),
-                ty::Uint(other) => Int::Unsigned(other),
-                ty::Error => { // Avoid ICE (#51963)
-                    return Err(LitToConstError::Propagated);
-                }
-                _ => bug!("literal integer type with bad type ({:?})", ty.sty),
-            };
-            // This converts from LitKind::Int (which is sign extended) to
-            // Scalar::Bytes (which is zero extended)
-            let n = match ity {
-                // FIXME(oli-obk): are these casts correct?
-                Int::Signed(IntTy::I8) if neg =>
-                    (n as i8).overflowing_neg().0 as u8 as u128,
-                Int::Signed(IntTy::I16) if neg =>
-                    (n as i16).overflowing_neg().0 as u16 as u128,
-                Int::Signed(IntTy::I32) if neg =>
-                    (n as i32).overflowing_neg().0 as u32 as u128,
-                Int::Signed(IntTy::I64) if neg =>
-                    (n as i64).overflowing_neg().0 as u64 as u128,
-                Int::Signed(IntTy::I128) if neg =>
-                    (n as i128).overflowing_neg().0 as u128,
-                Int::Signed(IntTy::I8) | Int::Unsigned(UintTy::U8) => n as u8 as u128,
-                Int::Signed(IntTy::I16) | Int::Unsigned(UintTy::U16) => n as u16 as u128,
-                Int::Signed(IntTy::I32) | Int::Unsigned(UintTy::U32) => n as u32 as u128,
-                Int::Signed(IntTy::I64) | Int::Unsigned(UintTy::U64) => n as u64 as u128,
-                Int::Signed(IntTy::I128)| Int::Unsigned(UintTy::U128) => n,
-                _ => bug!(),
-            };
-            let size = tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size.bytes() as u8;
-            ConstValue::Scalar(Scalar::Bits {
-                bits: n,
-                size,
-            })
+        LitKind::Int(n, _) if neg => {
+            let n = n as i128;
+            let n = n.overflowing_neg().0;
+            trunc(n as u128)?
         },
+        LitKind::Int(n, _) => trunc(n)?,
         LitKind::Float(n, fty) => {
             parse_float(n, fty, neg).map_err(|_| LitToConstError::UnparseableFloat)?
         }