about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-10-05 03:06:33 +0000
committerbors <bors@rust-lang.org>2015-10-05 03:06:33 +0000
commitc298efdb1f5e9334c25dcc1ea98fcc35a0b4c05d (patch)
tree73f9126b129198f1c4e7f1da93f49f4b3f29def2
parent0db2bc63ba72b11db0112468a1c08ff68aaa6ada (diff)
parent7e1e830a6f6f32b053b71ac628c0fbf8698ad888 (diff)
downloadrust-c298efdb1f5e9334c25dcc1ea98fcc35a0b4c05d.tar.gz
rust-c298efdb1f5e9334c25dcc1ea98fcc35a0b4c05d.zip
Auto merge of #28748 - nikomatsakis:universal-mir, r=pnkfelix
I had to fix a few things. Notable changes:

1. I removed the MIR support for constants, instead falling back to the existing `ConstVal`. I still think we ought to reform how we handle constants, but it's not clear to me that the approach I was taking is correct, and anyway I think we ought to do it separately.
2. I adjusted how we handle bindings in matches: we now *declare* all the bindings up front, rather than doing it as we encounter them. This is not only simpler, since we don't have to check if a binding has already been declared, it avoids ICEs if any of the arms turn out to be unreachable.
3. I do MIR construction *after* `check_match`, because it detects various broken cases. I'd like for `check_match` to be subsumed by MIR construction, but we can do that as a separate PR (if indeed it makes sense).

I did a crater run and found no regressions in the wild: https://gist.github.com/nikomatsakis/0038f90e10c8ad00f2f8
-rw-r--r--src/librustc/middle/const_eval.rs24
-rw-r--r--src/librustc_driver/driver.rs6
-rw-r--r--src/librustc_mir/build/expr/as_constant.rs97
-rw-r--r--src/librustc_mir/build/expr/into.rs6
-rw-r--r--src/librustc_mir/build/matches/mod.rs130
-rw-r--r--src/librustc_mir/build/matches/test.rs18
-rw-r--r--src/librustc_mir/build/misc.rs29
-rw-r--r--src/librustc_mir/build/stmt.rs2
-rw-r--r--src/librustc_mir/dump.rs2
-rw-r--r--src/librustc_mir/hair.rs14
-rw-r--r--src/librustc_mir/repr.rs41
-rw-r--r--src/librustc_mir/tcx/expr.rs70
-rw-r--r--src/librustc_mir/tcx/mod.rs14
-rw-r--r--src/librustc_mir/tcx/pattern.rs42
14 files changed, 201 insertions, 294 deletions
diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs
index e275ac7bc7d..acda0fe2f0e 100644
--- a/src/librustc/middle/const_eval.rs
+++ b/src/librustc/middle/const_eval.rs
@@ -38,6 +38,7 @@ use std::borrow::{Cow, IntoCow};
 use std::num::wrapping::OverflowingOps;
 use std::cmp::Ordering;
 use std::collections::hash_map::Entry::Vacant;
+use std::mem::transmute;
 use std::{i8, i16, i32, i64, u8, u16, u32, u64};
 use std::rc::Rc;
 
@@ -242,7 +243,7 @@ pub fn lookup_const_fn_by_id<'tcx>(tcx: &ty::ctxt<'tcx>, def_id: DefId)
     }
 }
 
-#[derive(Clone, PartialEq)]
+#[derive(Clone, Debug)]
 pub enum ConstVal {
     Float(f64),
     Int(i64),
@@ -254,6 +255,27 @@ pub enum ConstVal {
     Tuple(ast::NodeId),
 }
 
+/// Note that equality for `ConstVal` means that the it is the same
+/// constant, not that the rust values are equal. In particular, `NaN
+/// == NaN` (at least if it's the same NaN; distinct encodings for NaN
+/// are considering unequal).
+impl PartialEq for ConstVal {
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn eq(&self, other: &ConstVal) -> bool {
+        match (self, other) {
+            (&Float(a), &Float(b)) => unsafe{transmute::<_,u64>(a) == transmute::<_,u64>(b)},
+            (&Int(a), &Int(b)) => a == b,
+            (&Uint(a), &Uint(b)) => a == b,
+            (&Str(ref a), &Str(ref b)) => a == b,
+            (&ByteStr(ref a), &ByteStr(ref b)) => a == b,
+            (&Bool(a), &Bool(b)) => a == b,
+            (&Struct(a), &Struct(b)) => a == b,
+            (&Tuple(a), &Tuple(b)) => a == b,
+            _ => false,
+        }
+    }
+}
+
 impl ConstVal {
     pub fn description(&self) -> &'static str {
         match *self {
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 97fb6c3d26f..64d09a23658 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -718,9 +718,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: Session,
         // passes are timed inside typeck
         typeck::check_crate(tcx, trait_map);
 
-        time(time_passes, "MIR dump", ||
-             mir::dump::dump_crate(tcx));
-
         time(time_passes, "const checking", ||
             middle::check_const::check_crate(tcx));
 
@@ -741,6 +738,9 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: Session,
         time(time_passes, "match checking", ||
             middle::check_match::check_crate(tcx));
 
+        time(time_passes, "MIR dump", ||
+             mir::dump::dump_crate(tcx));
+
         time(time_passes, "liveness checking", ||
             middle::liveness::check_crate(tcx));
 
diff --git a/src/librustc_mir/build/expr/as_constant.rs b/src/librustc_mir/build/expr/as_constant.rs
index 5d20fe4bab4..6cc99a56933 100644
--- a/src/librustc_mir/build/expr/as_constant.rs
+++ b/src/librustc_mir/build/expr/as_constant.rs
@@ -10,8 +10,6 @@
 
 //! See docs in build/expr/mod.rs
 
-use rustc_data_structures::fnv::FnvHashMap;
-
 use build::{Builder};
 use hair::*;
 use repr::*;
@@ -28,93 +26,16 @@ impl<H:Hair> Builder<H> {
 
     fn expr_as_constant(&mut self, expr: Expr<H>) -> Constant<H> {
         let this = self;
-        let Expr { ty: _, temp_lifetime: _, span, kind } = expr;
-        let kind = match kind {
-            ExprKind::Scope { extent: _, value } => {
-                return this.as_constant(value);
-            }
-            ExprKind::Literal { literal } => {
-                ConstantKind::Literal(literal)
-            }
-            ExprKind::Vec { fields } => {
-                let fields = this.as_constants(fields);
-                ConstantKind::Aggregate(AggregateKind::Vec, fields)
-            }
-            ExprKind::Tuple { fields } => {
-                let fields = this.as_constants(fields);
-                ConstantKind::Aggregate(AggregateKind::Tuple, fields)
-            }
-            ExprKind::Adt { adt_def, variant_index, substs, fields, base: None } => {
-                let field_names = this.hir.fields(adt_def, variant_index);
-                let fields = this.named_field_constants(field_names, fields);
-                ConstantKind::Aggregate(AggregateKind::Adt(adt_def, variant_index, substs), fields)
-            }
-            ExprKind::Repeat { value, count } => {
-                let value = Box::new(this.as_constant(value));
-                let count = Box::new(this.as_constant(count));
-                ConstantKind::Repeat(value, count)
-            }
-            ExprKind::Binary { op, lhs, rhs } => {
-                let lhs = Box::new(this.as_constant(lhs));
-                let rhs = Box::new(this.as_constant(rhs));
-                ConstantKind::BinaryOp(op, lhs, rhs)
-            }
-            ExprKind::Unary { op, arg } => {
-                let arg = Box::new(this.as_constant(arg));
-                ConstantKind::UnaryOp(op, arg)
-            }
-            ExprKind::Field { lhs, name } => {
-                let lhs = this.as_constant(lhs);
-                ConstantKind::Projection(
-                    Box::new(ConstantProjection {
-                        base: lhs,
-                        elem: ProjectionElem::Field(name),
-                    }))
-            }
-            ExprKind::Deref { arg } => {
-                let arg = this.as_constant(arg);
-                ConstantKind::Projection(
-                    Box::new(ConstantProjection {
-                        base: arg,
-                        elem: ProjectionElem::Deref,
-                    }))
-            }
-            ExprKind::Call { fun, args } => {
-                let fun = this.as_constant(fun);
-                let args = this.as_constants(args);
-                ConstantKind::Call(Box::new(fun), args)
-            }
-            _ => {
+        let Expr { ty, temp_lifetime: _, span, kind } = expr;
+        match kind {
+            ExprKind::Scope { extent: _, value } =>
+                this.as_constant(value),
+            ExprKind::Literal { literal } =>
+                Constant { span: span, ty: ty, literal: literal },
+            _ =>
                 this.hir.span_bug(
                     span,
-                    &format!("expression is not a valid constant {:?}", kind));
-            }
-        };
-        Constant { span: span, kind: kind }
-    }
-
-    fn as_constants(&mut self,
-                    exprs: Vec<ExprRef<H>>)
-                    -> Vec<Constant<H>>
-    {
-        exprs.into_iter().map(|expr| self.as_constant(expr)).collect()
-    }
-
-    fn named_field_constants(&mut self,
-                             field_names: Vec<Field<H>>,
-                             field_exprs: Vec<FieldExprRef<H>>)
-                             -> Vec<Constant<H>>
-    {
-        let fields_map: FnvHashMap<_, _> =
-            field_exprs.into_iter()
-                       .map(|f| (f.name, self.as_constant(f.expr)))
-                       .collect();
-
-        let fields: Vec<_> =
-            field_names.into_iter()
-                       .map(|n| fields_map[&n].clone())
-                       .collect();
-
-        fields
+                    &format!("expression is not a valid constant {:?}", kind)),
+        }
     }
 }
diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs
index 72e505f2b6e..61eeac30c0f 100644
--- a/src/librustc_mir/build/expr/into.rs
+++ b/src/librustc_mir/build/expr/into.rs
@@ -99,14 +99,16 @@ impl<H:Hair> Builder<H> {
                     true_block, expr_span, destination,
                     Constant {
                         span: expr_span,
-                        kind: ConstantKind::Literal(Literal::Bool { value: true }),
+                        ty: this.hir.bool_ty(),
+                        literal: this.hir.true_literal(),
                     });
 
                 this.cfg.push_assign_constant(
                     false_block, expr_span, destination,
                     Constant {
                         span: expr_span,
-                        kind: ConstantKind::Literal(Literal::Bool { value: false }),
+                        ty: this.hir.bool_ty(),
+                        literal: this.hir.false_literal(),
                     });
 
                 this.cfg.terminate(true_block, Terminator::Goto { target: join_block });
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index 2ff57a18712..4d0acd5fac9 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -34,10 +34,20 @@ impl<H:Hair> Builder<H> {
         let discriminant_lvalue =
             unpack!(block = self.as_lvalue(block, discriminant));
 
-        let arm_blocks: Vec<BasicBlock> =
-            arms.iter()
-                .map(|_| self.cfg.start_new_block())
-                .collect();
+        // Before we do anything, create uninitialized variables with
+        // suitable extent for all of the bindings in this match. It's
+        // easiest to do this up front because some of these arms may
+        // be unreachable or reachable multiple times.
+        let var_extent = self.extent_of_innermost_scope().unwrap();
+        for arm in &arms {
+            self.declare_bindings(var_extent, arm.patterns[0].clone());
+        }
+
+        let mut arm_blocks = ArmBlocks {
+            blocks: arms.iter()
+                        .map(|_| self.cfg.start_new_block())
+                        .collect(),
+        };
 
         let arm_bodies: Vec<ExprRef<H>> =
             arms.iter()
@@ -51,35 +61,33 @@ impl<H:Hair> Builder<H> {
         // reverse of the order in which candidates are written in the
         // source.
         let candidates: Vec<Candidate<H>> =
-            arms.into_iter()
-                .zip(arm_blocks.iter())
+            arms.iter()
+                .enumerate()
                 .rev() // highest priority comes last
-                .flat_map(|(arm, &arm_block)| {
-                    let guard = arm.guard;
-                    arm.patterns.into_iter()
+                .flat_map(|(arm_index, arm)| {
+                    arm.patterns.iter()
                                 .rev()
-                                .map(move |pat| (arm_block, pat, guard.clone()))
+                                .map(move |pat| (arm_index, pat.clone(), arm.guard.clone()))
                 })
-                .map(|(arm_block, pattern, guard)| {
+                .map(|(arm_index, pattern, guard)| {
                     Candidate {
                         match_pairs: vec![self.match_pair(discriminant_lvalue.clone(), pattern)],
                         bindings: vec![],
                         guard: guard,
-                        arm_block: arm_block,
+                        arm_index: arm_index,
                     }
                 })
                 .collect();
 
         // this will generate code to test discriminant_lvalue and
         // branch to the appropriate arm block
-        let var_extent = self.extent_of_innermost_scope().unwrap();
-        self.match_candidates(span, var_extent, candidates, block);
+        self.match_candidates(span, &mut arm_blocks, candidates, block);
 
         // all the arm blocks will rejoin here
         let end_block = self.cfg.start_new_block();
 
-        for (arm_body, &arm_block) in arm_bodies.into_iter().zip(arm_blocks.iter()) {
-            let mut arm_block = arm_block;
+        for (arm_index, arm_body) in arm_bodies.into_iter().enumerate() {
+            let mut arm_block = arm_blocks.blocks[arm_index];
             unpack!(arm_block = self.into(destination, arm_block, arm_body));
             self.cfg.terminate(arm_block, Terminator::Goto { target: end_block });
         }
@@ -122,12 +130,15 @@ impl<H:Hair> Builder<H> {
                                initializer: &Lvalue<H>)
                                -> BlockAnd<()>
     {
+        // first, creating the bindings
+        self.declare_bindings(var_extent, irrefutable_pat.clone());
+
         // create a dummy candidate
         let mut candidate = Candidate::<H> {
-            match_pairs: vec![self.match_pair(initializer.clone(), irrefutable_pat)],
+            match_pairs: vec![self.match_pair(initializer.clone(), irrefutable_pat.clone())],
             bindings: vec![],
             guard: None,
-            arm_block: block
+            arm_index: 0, // since we don't call `match_candidates`, this field is unused
         };
 
         // Simplify the candidate. Since the pattern is irrefutable, this should
@@ -142,44 +153,50 @@ impl<H:Hair> Builder<H> {
         }
 
         // now apply the bindings, which will also declare the variables
-        self.bind_matched_candidate(block, var_extent, candidate.bindings);
+        self.bind_matched_candidate(block, candidate.bindings);
 
         block.unit()
     }
 
-    pub fn declare_uninitialized_variables(&mut self,
-                                           var_extent: H::CodeExtent,
-                                           pattern: PatternRef<H>)
+    pub fn declare_bindings(&mut self,
+                            var_extent: H::CodeExtent,
+                            pattern: PatternRef<H>)
     {
         let pattern = self.hir.mirror(pattern);
         match pattern.kind {
             PatternKind::Binding { mutability, name, mode: _, var, ty, subpattern } => {
                 self.declare_binding(var_extent, mutability, name, var, ty, pattern.span);
                 if let Some(subpattern) = subpattern {
-                    self.declare_uninitialized_variables(var_extent, subpattern);
+                    self.declare_bindings(var_extent, subpattern);
                 }
             }
             PatternKind::Array { prefix, slice, suffix } |
             PatternKind::Slice { prefix, slice, suffix } => {
                 for subpattern in prefix.into_iter().chain(slice).chain(suffix) {
-                    self.declare_uninitialized_variables(var_extent, subpattern);
+                    self.declare_bindings(var_extent, subpattern);
                 }
             }
             PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {
             }
             PatternKind::Deref { subpattern } => {
-                self.declare_uninitialized_variables(var_extent, subpattern);
+                self.declare_bindings(var_extent, subpattern);
             }
             PatternKind::Leaf { subpatterns } |
             PatternKind::Variant { subpatterns, .. } => {
                 for subpattern in subpatterns {
-                    self.declare_uninitialized_variables(var_extent, subpattern.pattern);
+                    self.declare_bindings(var_extent, subpattern.pattern);
                 }
             }
         }
     }
 }
 
+/// List of blocks for each arm (and potentially other metadata in the
+/// future).
+struct ArmBlocks {
+    blocks: Vec<BasicBlock>,
+}
+
 #[derive(Clone, Debug)]
 struct Candidate<H:Hair> {
     // all of these must be satisfied...
@@ -191,8 +208,8 @@ struct Candidate<H:Hair> {
     // ...and the guard must be evaluated...
     guard: Option<ExprRef<H>>,
 
-    // ...and then we branch here.
-    arm_block: BasicBlock,
+    // ...and then we branch to arm with this index.
+    arm_index: usize,
 }
 
 #[derive(Clone, Debug)]
@@ -221,10 +238,10 @@ enum TestKind<H:Hair> {
     Switch { adt_def: H::AdtDef },
 
     // test for equality
-    Eq { value: Constant<H>, ty: H::Ty },
+    Eq { value: Literal<H>, ty: H::Ty },
 
     // test whether the value falls within an inclusive range
-    Range { lo: Constant<H>, hi: Constant<H>, ty: H::Ty },
+    Range { lo: Literal<H>, hi: Literal<H>, ty: H::Ty },
 
     // test length of the slice is equal to len
     Len { len: usize, op: BinOp },
@@ -242,12 +259,12 @@ struct Test<H:Hair> {
 impl<H:Hair> Builder<H> {
     fn match_candidates(&mut self,
                         span: H::Span,
-                        var_extent: H::CodeExtent,
+                        arm_blocks: &mut ArmBlocks,
                         mut candidates: Vec<Candidate<H>>,
                         mut block: BasicBlock)
     {
-        debug!("matched_candidate(span={:?}, var_extent={:?}, block={:?}, candidates={:?})",
-               span, var_extent, block, candidates);
+        debug!("matched_candidate(span={:?}, block={:?}, candidates={:?})",
+               span, block, candidates);
 
         // Start by simplifying candidates. Once this process is
         // complete, all the match pairs which remain require some
@@ -267,9 +284,12 @@ impl<H:Hair> Builder<H> {
             // If so, apply any bindings, test the guard (if any), and
             // branch to the arm.
             let candidate = candidates.pop().unwrap();
-            match self.bind_and_guard_matched_candidate(block, var_extent, candidate) {
-                None => { return; }
-                Some(b) => { block = b; }
+            if let Some(b) = self.bind_and_guard_matched_candidate(block, arm_blocks, candidate) {
+                block = b;
+            } else {
+                // if None is returned, then any remaining candidates
+                // are unreachable (at least not through this path).
+                return;
             }
         }
 
@@ -297,7 +317,7 @@ impl<H:Hair> Builder<H> {
                                                                       candidate))
                           })
                           .collect();
-            self.match_candidates(span, var_extent, applicable_candidates, target_block);
+            self.match_candidates(span, arm_blocks, applicable_candidates, target_block);
         }
     }
 
@@ -315,15 +335,17 @@ impl<H:Hair> Builder<H> {
     /// MIR).
     fn bind_and_guard_matched_candidate(&mut self,
                                         mut block: BasicBlock,
-                                        var_extent: H::CodeExtent,
+                                        arm_blocks: &mut ArmBlocks,
                                         candidate: Candidate<H>)
                                         -> Option<BasicBlock> {
-        debug!("bind_and_guard_matched_candidate(block={:?}, var_extent={:?}, candidate={:?})",
-               block, var_extent, candidate);
+        debug!("bind_and_guard_matched_candidate(block={:?}, candidate={:?})",
+               block, candidate);
 
         debug_assert!(candidate.match_pairs.is_empty());
 
-        self.bind_matched_candidate(block, var_extent, candidate.bindings);
+        self.bind_matched_candidate(block, candidate.bindings);
+
+        let arm_block = arm_blocks.blocks[candidate.arm_index];
 
         if let Some(guard) = candidate.guard {
             // the block to branch to if the guard fails; if there is no
@@ -331,36 +353,26 @@ impl<H:Hair> Builder<H> {
             let cond = unpack!(block = self.as_operand(block, guard));
             let otherwise = self.cfg.start_new_block();
             self.cfg.terminate(block, Terminator::If { cond: cond,
-                                                       targets: [candidate.arm_block, otherwise]});
+                                                       targets: [arm_block, otherwise]});
             Some(otherwise)
         } else {
-            self.cfg.terminate(block, Terminator::Goto { target: candidate.arm_block });
+            self.cfg.terminate(block, Terminator::Goto { target: arm_block });
             None
         }
     }
 
     fn bind_matched_candidate(&mut self,
                               block: BasicBlock,
-                              var_extent: H::CodeExtent,
                               bindings: Vec<Binding<H>>) {
-        debug!("bind_matched_candidate(block={:?}, var_extent={:?}, bindings={:?})",
-               block, var_extent, bindings);
+        debug!("bind_matched_candidate(block={:?}, bindings={:?})",
+               block, bindings);
 
         // Assign each of the bindings. This may trigger moves out of the candidate.
         for binding in bindings {
-            // Create a variable for the `var_id` being bound. In the
-            // case where there are multiple patterns for a single
-            // arm, it may already exist.
-            let var_index = if !self.var_indices.contains_key(&binding.var_id) {
-                self.declare_binding(var_extent,
-                                     binding.mutability,
-                                     binding.name,
-                                     binding.var_id,
-                                     binding.var_ty,
-                                     binding.span)
-            } else {
-                self.var_indices[&binding.var_id]
-            };
+            // Find the variable for the `var_id` being bound. It
+            // should have been created by a previous call to
+            // `declare_bindings`.
+            let var_index = self.var_indices[&binding.var_id];
 
             let rvalue = match binding.binding_mode {
                 BindingMode::ByValue =>
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index 2d0a6e61beb..2d034baef16 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -33,20 +33,20 @@ impl<H:Hair> Builder<H> {
                 }
             }
 
-            PatternKind::Constant { ref expr } => {
-                let expr = self.as_constant(expr.clone());
+            PatternKind::Constant { ref value } => {
                 Test {
                     span: match_pair.pattern.span,
-                    kind: TestKind::Eq { value: expr, ty: match_pair.pattern.ty.clone() },
+                    kind: TestKind::Eq { value: value.clone(),
+                                         ty: match_pair.pattern.ty.clone() },
                 }
             }
 
             PatternKind::Range { ref lo, ref hi } => {
-                let lo = self.as_constant(lo.clone());
-                let hi = self.as_constant(hi.clone());
                 Test {
                     span: match_pair.pattern.span,
-                    kind: TestKind::Range { lo: lo, hi: hi, ty: match_pair.pattern.ty.clone() },
+                    kind: TestKind::Range { lo: lo.clone(),
+                                            hi: hi.clone(),
+                                            ty: match_pair.pattern.ty.clone() },
                 }
             }
 
@@ -90,15 +90,15 @@ impl<H:Hair> Builder<H> {
 
             TestKind::Eq { value, ty } => {
                 // call PartialEq::eq(discrim, constant)
-                let constant = self.push_constant(block, test.span, ty.clone(), value);
+                let constant = self.push_literal(block, test.span, ty.clone(), value);
                 let item_ref = self.hir.partial_eq(ty);
                 self.call_comparison_fn(block, test.span, item_ref, lvalue.clone(), constant)
             }
 
             TestKind::Range { lo, hi, ty } => {
                 // Test `v` by computing `PartialOrd::le(lo, v) && PartialOrd::le(v, hi)`.
-                let lo = self.push_constant(block, test.span, ty.clone(), lo);
-                let hi = self.push_constant(block, test.span, ty.clone(), hi);
+                let lo = self.push_literal(block, test.span, ty.clone(), lo);
+                let hi = self.push_literal(block, test.span, ty.clone(), hi);
                 let item_ref = self.hir.partial_le(ty);
 
                 let lo_blocks =
diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs
index 1c44988e4b4..9fa1d55e82f 100644
--- a/src/librustc_mir/build/misc.rs
+++ b/src/librustc_mir/build/misc.rs
@@ -33,13 +33,14 @@ impl<H:Hair> Builder<H> {
         lvalue
     }
 
-    pub fn push_constant(&mut self,
-                         block: BasicBlock,
-                         span: H::Span,
-                         ty: H::Ty,
-                         constant: Constant<H>)
-                         -> Lvalue<H> {
-        let temp = self.temp(ty);
+    pub fn push_literal(&mut self,
+                        block: BasicBlock,
+                        span: H::Span,
+                        ty: H::Ty,
+                        literal: Literal<H>)
+                        -> Lvalue<H> {
+        let temp = self.temp(ty.clone());
+        let constant = Constant { span: span, ty: ty, literal: literal };
         self.cfg.push_assign_constant(block, span, &temp, constant);
         temp
     }
@@ -55,8 +56,8 @@ impl<H:Hair> Builder<H> {
             block, span, &temp,
             Constant {
                 span: span,
-                kind: ConstantKind::Literal(Literal::Uint { bits: IntegralBits::BSize,
-                                                            value: value as u64 }),
+                ty: self.hir.usize_ty(),
+                literal: self.hir.usize_literal(value),
             });
         temp
     }
@@ -66,13 +67,7 @@ impl<H:Hair> Builder<H> {
                          span: H::Span,
                          item_ref: ItemRef<H>)
                          -> Lvalue<H> {
-        let constant = Constant {
-            span: span,
-            kind: ConstantKind::Literal(Literal::Item {
-                def_id: item_ref.def_id,
-                substs: item_ref.substs
-            })
-        };
-        self.push_constant(block, span, item_ref.ty, constant)
+        let literal = Literal::Item { def_id: item_ref.def_id, substs: item_ref.substs };
+        self.push_literal(block, span, item_ref.ty, literal)
     }
 }
diff --git a/src/librustc_mir/build/stmt.rs b/src/librustc_mir/build/stmt.rs
index 9d5a83154d4..3dd4f5f253c 100644
--- a/src/librustc_mir/build/stmt.rs
+++ b/src/librustc_mir/build/stmt.rs
@@ -40,7 +40,7 @@ impl<H:Hair> Builder<H> {
             StmtKind::Let { remainder_scope, init_scope, pattern, initializer: None, stmts } => {
                 this.in_scope(remainder_scope, block, |this| {
                     unpack!(block = this.in_scope(init_scope, block, |this| {
-                        this.declare_uninitialized_variables(remainder_scope, pattern);
+                        this.declare_bindings(remainder_scope, pattern);
                         block.unit()
                     }));
                     this.stmts(block, stmts)
diff --git a/src/librustc_mir/dump.rs b/src/librustc_mir/dump.rs
index ebde7e1d097..4251b550cfc 100644
--- a/src/librustc_mir/dump.rs
+++ b/src/librustc_mir/dump.rs
@@ -62,7 +62,7 @@ impl<'a, 'tcx> OuterDump<'a, 'tcx> {
             }
         }
 
-        let always_build_mir = self.tcx.sess.opts.always_build_mir;
+        let always_build_mir = true;
         if !built_mir && always_build_mir {
             let mut closure_dump = InnerDump { tcx: self.tcx, attr: None };
             walk_op(&mut closure_dump);
diff --git a/src/librustc_mir/hair.rs b/src/librustc_mir/hair.rs
index cb094ad4905..f4eb03c5d07 100644
--- a/src/librustc_mir/hair.rs
+++ b/src/librustc_mir/hair.rs
@@ -38,6 +38,7 @@ pub trait Hair: Sized+Debug+Clone+Eq+Hash { // (*)
     type Ty: Clone+Debug+Eq;                                     // e.g., ty::Ty<'tcx>
     type Region: Copy+Debug;                                     // e.g., ty::Region
     type CodeExtent: Copy+Debug+Hash+Eq;                         // e.g., region::CodeExtent
+    type ConstVal: Clone+Debug+PartialEq;                        // e.g., ConstVal
     type Pattern: Clone+Debug+Mirror<Self,Output=Pattern<Self>>; // e.g., &P<ast::Pat>
     type Expr: Clone+Debug+Mirror<Self,Output=Expr<Self>>;       // e.g., &P<ast::Expr>
     type Stmt: Clone+Debug+Mirror<Self,Output=Stmt<Self>>;       // e.g., &P<ast::Stmt>
@@ -55,9 +56,18 @@ pub trait Hair: Sized+Debug+Clone+Eq+Hash { // (*)
     /// Returns the type `usize`.
     fn usize_ty(&mut self) -> Self::Ty;
 
+    /// Returns the literal for `true`
+    fn usize_literal(&mut self, value: usize) -> Literal<Self>;
+
     /// Returns the type `bool`.
     fn bool_ty(&mut self) -> Self::Ty;
 
+    /// Returns the literal for `true`
+    fn true_literal(&mut self) -> Literal<Self>;
+
+    /// Returns the literal for `true`
+    fn false_literal(&mut self) -> Literal<Self>;
+
     /// Returns a reference to `PartialEq::<T,T>::eq`
     fn partial_eq(&mut self, ty: Self::Ty) -> ItemRef<Self>;
 
@@ -261,9 +271,9 @@ pub enum PatternKind<H:Hair> {
 
     Deref { subpattern: PatternRef<H> }, // box P, &P, &mut P, etc
 
-    Constant { expr: ExprRef<H> },
+    Constant { value: Literal<H> },
 
-    Range { lo: ExprRef<H>, hi: ExprRef<H> },
+    Range { lo: Literal<H>, hi: Literal<H> },
 
     // matches against a slice, checking the length and extracting elements
     Slice { prefix: Vec<PatternRef<H>>,
diff --git a/src/librustc_mir/repr.rs b/src/librustc_mir/repr.rs
index a1b891ab090..d522518a3d4 100644
--- a/src/librustc_mir/repr.rs
+++ b/src/librustc_mir/repr.rs
@@ -642,48 +642,21 @@ impl<H:Hair> Debug for Rvalue<H> {
 
 ///////////////////////////////////////////////////////////////////////////
 // Constants
+//
+// Two constants are equal if they are the same constant. Note that
+// this does not necessarily mean that they are "==" in Rust -- in
+// particular one must be wary of `NaN`!
 
 #[derive(Clone, Debug, PartialEq)]
 pub struct Constant<H:Hair> {
     pub span: H::Span,
-    pub kind: ConstantKind<H>
+    pub ty: H::Ty,
+    pub literal: Literal<H>
 }
 
 #[derive(Clone, Debug, PartialEq)]
-pub enum ConstantKind<H:Hair> {
-    Literal(Literal<H>),
-    Aggregate(AggregateKind<H>, Vec<Constant<H>>),
-    Call(Box<Constant<H>>, Vec<Constant<H>>),
-    Cast(Box<Constant<H>>, H::Ty),
-    Repeat(Box<Constant<H>>, Box<Constant<H>>),
-    Ref(BorrowKind, Box<Constant<H>>),
-    BinaryOp(BinOp, Box<Constant<H>>, Box<Constant<H>>),
-    UnaryOp(UnOp, Box<Constant<H>>),
-    Projection(Box<ConstantProjection<H>>)
-}
-
-pub type ConstantProjection<H> =
-    Projection<H,Constant<H>,Constant<H>>;
-
-#[derive(Clone, Debug, PartialEq)]
 pub enum Literal<H:Hair> {
     Item { def_id: H::DefId, substs: H::Substs },
-    Projection { projection: H::Projection },
-    Int { bits: IntegralBits, value: i64 },
-    Uint { bits: IntegralBits, value: u64 },
-    Float { bits: FloatBits, value: f64 },
-    Char { c: char },
-    Bool { value: bool },
-    Bytes { value: H::Bytes },
-    String { value: H::InternedString },
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
-pub enum IntegralBits {
-    B8, B16, B32, B64, BSize
+    Value { value: H::ConstVal },
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
-pub enum FloatBits {
-    F32, F64
-}
diff --git a/src/librustc_mir/tcx/expr.rs b/src/librustc_mir/tcx/expr.rs
index 97becd474b1..098a85514eb 100644
--- a/src/librustc_mir/tcx/expr.rs
+++ b/src/librustc_mir/tcx/expr.rs
@@ -16,14 +16,13 @@ use tcx::Cx;
 use tcx::block;
 use tcx::pattern::PatNode;
 use tcx::rustc::front::map;
+use tcx::rustc::middle::const_eval;
 use tcx::rustc::middle::def;
 use tcx::rustc::middle::region::CodeExtent;
 use tcx::rustc::middle::pat_util;
 use tcx::rustc::middle::ty::{self, Ty};
 use tcx::rustc_front::hir;
 use tcx::rustc_front::util as hir_util;
-use tcx::syntax::ast;
-use tcx::syntax::codemap::Span;
 use tcx::syntax::parse::token;
 use tcx::syntax::ptr::P;
 use tcx::to_ref::ToRef;
@@ -83,9 +82,9 @@ impl<'a,'tcx:'a> Mirror<Cx<'a,'tcx>> for &'tcx hir::Expr {
                 }
             }
 
-            hir::ExprLit(ref lit) => {
-                let literal = convert_literal(cx, self.span, expr_ty, lit);
-                ExprKind::Literal { literal: literal }
+            hir::ExprLit(..) => {
+                let value = const_eval::eval_const_expr(cx.tcx, self);
+                ExprKind::Literal { literal: Literal::Value { value: value } }
             }
 
             hir::ExprBinary(op, ref lhs, ref rhs) => {
@@ -452,67 +451,6 @@ fn to_borrow_kind(m: hir::Mutability) -> BorrowKind {
     }
 }
 
-fn convert_literal<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>,
-                               expr_span: Span,
-                               expr_ty: Ty<'tcx>,
-                               literal: &ast::Lit)
-                               -> Literal<Cx<'a,'tcx>>
-{
-    use repr::IntegralBits::*;
-    match (&literal.node, &expr_ty.sty) {
-        (&ast::LitStr(ref text, _), _) =>
-            Literal::String { value: text.clone() },
-        (&ast::LitByteStr(ref bytes), _) =>
-            Literal::Bytes { value: bytes.clone() },
-        (&ast::LitByte(c), _) =>
-            Literal::Uint { bits: B8, value: c as u64 },
-        (&ast::LitChar(c), _) =>
-            Literal::Char { c: c },
-        (&ast::LitInt(v, _), &ty::TyUint(ast::TyU8)) =>
-            Literal::Uint { bits: B8, value: v },
-        (&ast::LitInt(v, _), &ty::TyUint(ast::TyU16)) =>
-            Literal::Uint { bits: B16, value: v },
-        (&ast::LitInt(v, _), &ty::TyUint(ast::TyU32)) =>
-            Literal::Uint { bits: B32, value: v },
-        (&ast::LitInt(v, _), &ty::TyUint(ast::TyU64)) =>
-            Literal::Uint { bits: B64, value: v },
-        (&ast::LitInt(v, _), &ty::TyUint(ast::TyUs)) =>
-            Literal::Uint { bits: BSize, value: v },
-        (&ast::LitInt(v, ast::SignedIntLit(_, ast::Sign::Minus)), &ty::TyInt(ast::TyI8)) =>
-            Literal::Int { bits: B8, value: -(v as i64) },
-        (&ast::LitInt(v, ast::SignedIntLit(_, ast::Sign::Minus)), &ty::TyInt(ast::TyI16)) =>
-            Literal::Int { bits: B16, value: -(v as i64) },
-        (&ast::LitInt(v, ast::SignedIntLit(_, ast::Sign::Minus)), &ty::TyInt(ast::TyI32)) =>
-            Literal::Int { bits: B32, value: -(v as i64) },
-        (&ast::LitInt(v, ast::SignedIntLit(_, ast::Sign::Minus)), &ty::TyInt(ast::TyI64)) =>
-            Literal::Int { bits: B64, value: -(v as i64) },
-        (&ast::LitInt(v, ast::SignedIntLit(_, ast::Sign::Minus)), &ty::TyInt(ast::TyIs)) =>
-            Literal::Int { bits: BSize, value: -(v as i64) },
-        (&ast::LitInt(v, _), &ty::TyInt(ast::TyI8)) =>
-            Literal::Int { bits: B8, value: v as i64 },
-        (&ast::LitInt(v, _), &ty::TyInt(ast::TyI16)) =>
-            Literal::Int { bits: B16, value: v as i64 },
-        (&ast::LitInt(v, _), &ty::TyInt(ast::TyI32)) =>
-            Literal::Int { bits: B32, value: v as i64 },
-        (&ast::LitInt(v, _), &ty::TyInt(ast::TyI64)) =>
-            Literal::Int { bits: B64, value: v as i64 },
-        (&ast::LitInt(v, _), &ty::TyInt(ast::TyIs)) =>
-            Literal::Int { bits: BSize, value: v as i64 },
-        (&ast::LitFloat(ref v, _), &ty::TyFloat(ast::TyF32)) |
-        (&ast::LitFloatUnsuffixed(ref v), &ty::TyFloat(ast::TyF32)) =>
-            Literal::Float { bits: FloatBits::F32, value: v.parse::<f64>().unwrap() },
-        (&ast::LitFloat(ref v, _), &ty::TyFloat(ast::TyF64)) |
-        (&ast::LitFloatUnsuffixed(ref v), &ty::TyFloat(ast::TyF64)) =>
-            Literal::Float { bits: FloatBits::F64, value: v.parse::<f64>().unwrap() },
-        (&ast::LitBool(v), _) =>
-            Literal::Bool { value: v },
-        (ref l, ref t) =>
-            cx.tcx.sess.span_bug(
-                expr_span,
-                &format!("Invalid literal/type combination: {:?},{:?}", l, t))
-    }
-}
-
 fn convert_arm<'a,'tcx:'a>(cx: &Cx<'a,'tcx>, arm: &'tcx hir::Arm) -> Arm<Cx<'a,'tcx>> {
     let map = if arm.pats.len() == 1 {
         None
diff --git a/src/librustc_mir/tcx/mod.rs b/src/librustc_mir/tcx/mod.rs
index 9c0ef55b3d8..04f52a52464 100644
--- a/src/librustc_mir/tcx/mod.rs
+++ b/src/librustc_mir/tcx/mod.rs
@@ -14,6 +14,7 @@ use std::fmt::{Debug, Formatter, Error};
 use std::hash::{Hash, Hasher};
 use std::rc::Rc;
 
+use self::rustc::middle::const_eval::ConstVal;
 use self::rustc::middle::def_id::DefId;
 use self::rustc::middle::infer::InferCtxt;
 use self::rustc::middle::region::CodeExtent;
@@ -56,6 +57,7 @@ impl<'a,'tcx:'a> Hair for Cx<'a, 'tcx> {
     type Ty = Ty<'tcx>;
     type Region = ty::Region;
     type CodeExtent = CodeExtent;
+    type ConstVal = ConstVal;
     type Pattern = PatNode<'tcx>;
     type Expr = &'tcx hir::Expr;
     type Stmt = &'tcx hir::Stmt;
@@ -70,10 +72,22 @@ impl<'a,'tcx:'a> Hair for Cx<'a, 'tcx> {
         self.tcx.types.usize
     }
 
+    fn usize_literal(&mut self, value: usize) -> Literal<Self> {
+        Literal::Value { value: ConstVal::Uint(value as u64) }
+    }
+
     fn bool_ty(&mut self) -> Ty<'tcx> {
         self.tcx.types.bool
     }
 
+    fn true_literal(&mut self) -> Literal<Self> {
+        Literal::Value { value: ConstVal::Bool(true) }
+    }
+
+    fn false_literal(&mut self) -> Literal<Self> {
+        Literal::Value { value: ConstVal::Bool(false) }
+    }
+
     fn partial_eq(&mut self, ty: Ty<'tcx>) -> ItemRef<Self> {
         let eq_def_id = self.tcx.lang_items.eq_trait().unwrap();
         self.cmp_method_ref(eq_def_id, "eq", ty)
diff --git a/src/librustc_mir/tcx/pattern.rs b/src/librustc_mir/tcx/pattern.rs
index d80fbfa7fe8..fe0c2c6c76a 100644
--- a/src/librustc_mir/tcx/pattern.rs
+++ b/src/librustc_mir/tcx/pattern.rs
@@ -14,9 +14,10 @@ use repr::*;
 use rustc_data_structures::fnv::FnvHashMap;
 use std::rc::Rc;
 use tcx::Cx;
-use tcx::rustc::middle::const_eval::lookup_const_by_id;
+use tcx::rustc::middle::const_eval;
 use tcx::rustc::middle::def;
 use tcx::rustc::middle::pat_util::{pat_is_resolved_const, pat_is_binding};
+use tcx::rustc::middle::subst::Substs;
 use tcx::rustc::middle::ty::{self, Ty};
 use tcx::rustc_front::hir;
 use tcx::syntax::ast;
@@ -145,12 +146,19 @@ impl<'a,'tcx:'a> Mirror<Cx<'a,'tcx>> for PatNode<'tcx> {
             hir::PatWild(..) =>
                 PatternKind::Wild,
 
-            hir::PatLit(ref lt) =>
-                PatternKind::Constant { expr: lt.to_ref() },
+            hir::PatLit(ref value) => {
+                let value = const_eval::eval_const_expr(cx.tcx, value);
+                let value = Literal::Value { value: value };
+                PatternKind::Constant { value: value }
+            },
 
-            hir::PatRange(ref begin, ref end) =>
-                PatternKind::Range { lo: begin.to_ref(),
-                                     hi: end.to_ref() },
+            hir::PatRange(ref lo, ref hi) => {
+                let lo = const_eval::eval_const_expr(cx.tcx, lo);
+                let lo = Literal::Value { value: lo };
+                let hi = const_eval::eval_const_expr(cx.tcx, hi);
+                let hi = Literal::Value { value: hi };
+                PatternKind::Range { lo: lo, hi: hi }
+            },
 
             hir::PatEnum(..) | hir::PatIdent(..) | hir::PatQPath(..)
                 if pat_is_resolved_const(&cx.tcx.def_map, self.pat) =>
@@ -158,13 +166,25 @@ impl<'a,'tcx:'a> Mirror<Cx<'a,'tcx>> for PatNode<'tcx> {
                 let def = cx.tcx.def_map.borrow().get(&self.pat.id).unwrap().full_def();
                 match def {
                     def::DefConst(def_id) | def::DefAssociatedConst(def_id) =>
-                        match lookup_const_by_id(cx.tcx, def_id, Some(self.pat.id)) {
-                            Some(const_expr) =>
-                                PatternKind::Constant { expr: const_expr.to_ref() },
-                            None =>
+                        match const_eval::lookup_const_by_id(cx.tcx, def_id, Some(self.pat.id)) {
+                            Some(const_expr) => {
+                                let opt_value =
+                                    const_eval::eval_const_expr_partial(
+                                        cx.tcx, const_expr,
+                                        const_eval::EvalHint::ExprTypeChecked);
+                                let literal = if let Ok(value) = opt_value {
+                                    Literal::Value { value: value }
+                                } else {
+                                    let substs = cx.tcx.mk_substs(Substs::empty());
+                                    Literal::Item { def_id: def_id, substs: substs }
+                                };
+                                PatternKind::Constant { value: literal }
+                            }
+                            None => {
                                 cx.tcx.sess.span_bug(
                                     self.pat.span,
-                                    &format!("cannot eval constant: {:?}", def_id)),
+                                    &format!("cannot eval constant: {:?}", def_id))
+                            }
                         },
                     _ =>
                         cx.tcx.sess.span_bug(