about summary refs log tree commit diff
diff options
context:
space:
mode:
authorOliver Schneider <git-spam-no-reply9815368754983@oli-obk.de>2016-03-30 13:43:36 +0200
committerOliver Schneider <git-spam-no-reply9815368754983@oli-obk.de>2016-03-30 13:43:36 +0200
commit3eac64747f520ec29195c9040348e028f22058aa (patch)
tree64e7d47781b5a33b63e3f80b0eb5e13ba13e9814
parent6cc449ad241c1cc54f5a789affffed2642422cec (diff)
downloadrust-3eac64747f520ec29195c9040348e028f22058aa.tar.gz
rust-3eac64747f520ec29195c9040348e028f22058aa.zip
move `const_eval` and `check_match` out of `librustc`
-rw-r--r--mk/crates.mk23
-rw-r--r--src/librustc/diagnostics.rs521
-rw-r--r--src/librustc/lib.rs3
-rw-r--r--src/librustc/middle/const_val.rs101
-rw-r--r--src/librustc/mir/repr.rs4
-rw-r--r--src/librustc/mir/visit.rs2
-rw-r--r--src/librustc/ty/util.rs37
-rw-r--r--src/librustc_const_eval/Cargo.toml19
-rw-r--r--src/librustc_const_eval/check_match.rs (renamed from src/librustc/middle/check_match.rs)56
-rw-r--r--src/librustc_const_eval/diagnostics.rs545
-rw-r--r--src/librustc_const_eval/eval.rs (renamed from src/librustc/middle/const_eval.rs)155
-rw-r--r--src/librustc_const_eval/lib.rs53
-rw-r--r--src/librustc_const_math/int.rs4
-rw-r--r--src/librustc_driver/Cargo.toml1
-rw-r--r--src/librustc_driver/driver.rs3
-rw-r--r--src/librustc_driver/lib.rs2
-rw-r--r--src/librustc_lint/Cargo.toml1
-rw-r--r--src/librustc_lint/lib.rs1
-rw-r--r--src/librustc_lint/types.rs5
-rw-r--r--src/librustc_mir/Cargo.toml1
-rw-r--r--src/librustc_mir/build/matches/mod.rs2
-rw-r--r--src/librustc_mir/build/matches/test.rs2
-rw-r--r--src/librustc_mir/build/scope.rs2
-rw-r--r--src/librustc_mir/hair/cx/expr.rs3
-rw-r--r--src/librustc_mir/hair/cx/mod.rs3
-rw-r--r--src/librustc_mir/hair/cx/pattern.rs2
-rw-r--r--src/librustc_mir/hair/mod.rs2
-rw-r--r--src/librustc_mir/lib.rs1
-rw-r--r--src/librustc_mir/transform/simplify_cfg.rs2
-rw-r--r--src/librustc_passes/Cargo.toml1
-rw-r--r--src/librustc_passes/consts.rs15
-rw-r--r--src/librustc_passes/lib.rs1
-rw-r--r--src/librustc_trans/Cargo.toml1
-rw-r--r--src/librustc_trans/_match.rs13
-rw-r--r--src/librustc_trans/consts.rs13
-rw-r--r--src/librustc_trans/lib.rs1
-rw-r--r--src/librustc_trans/mir/constant.rs5
-rw-r--r--src/librustc_trans/mir/rvalue.rs2
-rw-r--r--src/librustc_trans/tvec.rs5
-rw-r--r--src/librustc_typeck/Cargo.toml1
-rw-r--r--src/librustc_typeck/astconv.rs7
-rw-r--r--src/librustc_typeck/check/mod.rs3
-rw-r--r--src/librustc_typeck/collect.rs7
-rw-r--r--src/librustc_typeck/lib.rs1
-rw-r--r--src/librustdoc/Cargo.toml1
-rw-r--r--src/librustdoc/clean/inline.rs8
-rw-r--r--src/librustdoc/lib.rs1
-rw-r--r--src/test/auxiliary/dummy_mir_pass.rs2
48 files changed, 890 insertions, 754 deletions
diff --git a/mk/crates.mk b/mk/crates.mk
index 1b614595e2a..8c80335e772 100644
--- a/mk/crates.mk
+++ b/mk/crates.mk
@@ -58,7 +58,7 @@ RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_
                 rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \
                 rustc_data_structures rustc_front rustc_platform_intrinsics \
                 rustc_plugin rustc_metadata rustc_passes rustc_save_analysis \
-                rustc_const_eval
+                rustc_const_eval rustc_const_math
 HOST_CRATES := syntax syntax_ext $(RUSTC_CRATES) rustdoc fmt_macros \
 		flate arena graphviz rbml log serialize
 TOOLS := compiletest rustdoc rustc rustbook error_index_generator
@@ -93,35 +93,38 @@ DEPS_syntax := std term serialize log arena libc rustc_bitflags rustc_unicode
 DEPS_syntax_ext := syntax fmt_macros
 
 DEPS_rustc_const_math := std syntax log serialize
+DEPS_rustc_const_eval := rustc_const_math rustc syntax log serialize rustc_front \
+					     rustc_back graphviz
 
 DEPS_rustc := syntax fmt_macros flate arena serialize getopts rbml rustc_front\
               log graphviz rustc_back rustc_data_structures\
-		  	  rustc_const_eval
+		  	  rustc_const_math
 DEPS_rustc_back := std syntax rustc_front flate log libc
 DEPS_rustc_borrowck := rustc rustc_front rustc_mir log graphviz syntax
 DEPS_rustc_data_structures := std log serialize
 DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \
                      rustc_typeck rustc_mir rustc_resolve log syntax serialize rustc_llvm \
 	             rustc_trans rustc_privacy rustc_lint rustc_front rustc_plugin \
-                     rustc_metadata syntax_ext rustc_passes rustc_save_analysis
+                     rustc_metadata syntax_ext rustc_passes rustc_save_analysis rustc_const_eval
 DEPS_rustc_front := std syntax log serialize
-DEPS_rustc_lint := rustc log syntax
+DEPS_rustc_lint := rustc log syntax rustc_const_eval
 DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags
-DEPS_rustc_metadata := rustc rustc_front syntax rbml rustc_const_eval
-DEPS_rustc_passes := syntax rustc core rustc_front
-DEPS_rustc_mir := rustc rustc_front syntax rustc_const_eval
+DEPS_rustc_metadata := rustc rustc_front syntax rbml rustc_const_math
+DEPS_rustc_passes := syntax rustc core rustc_front rustc_const_eval
+DEPS_rustc_mir := rustc rustc_front syntax rustc_const_math rustc_const_eval
 DEPS_rustc_resolve := arena rustc rustc_front log syntax
 DEPS_rustc_platform_intrinsics := std
 DEPS_rustc_plugin := rustc rustc_metadata syntax rustc_mir
 DEPS_rustc_privacy := rustc rustc_front log syntax
 DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back rustc_mir \
                     log syntax serialize rustc_llvm rustc_front rustc_platform_intrinsics \
-					rustc_const_eval
+                    rustc_const_math rustc_const_eval
 DEPS_rustc_save_analysis := rustc log syntax rustc_front
-DEPS_rustc_typeck := rustc syntax rustc_front rustc_platform_intrinsics rustc_const_eval
+DEPS_rustc_typeck := rustc syntax rustc_front rustc_platform_intrinsics rustc_const_math \
+                     rustc_const_eval
 
 DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \
-                test rustc_lint rustc_front
+                test rustc_lint rustc_front rustc_const_eval
 
 
 TOOL_DEPS_compiletest := test getopts log
diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs
index 9348c05d444..117b1119c0a 100644
--- a/src/librustc/diagnostics.rs
+++ b/src/librustc/diagnostics.rs
@@ -14,273 +14,6 @@
 // Each message should start and end with a new line, and be wrapped to 80 characters.
 // In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
 register_long_diagnostics! {
-
-E0001: r##"
-This error suggests that the expression arm corresponding to the noted pattern
-will never be reached as for all possible values of the expression being
-matched, one of the preceding patterns will match.
-
-This means that perhaps some of the preceding patterns are too general, this
-one is too specific or the ordering is incorrect.
-
-For example, the following `match` block has too many arms:
-
-```compile_fail
-match foo {
-    Some(bar) => {/* ... */}
-    None => {/* ... */}
-    _ => {/* ... */} // All possible cases have already been handled
-}
-```
-
-`match` blocks have their patterns matched in order, so, for example, putting
-a wildcard arm above a more specific arm will make the latter arm irrelevant.
-
-Ensure the ordering of the match arm is correct and remove any superfluous
-arms.
-"##,
-
-E0002: r##"
-This error indicates that an empty match expression is invalid because the type
-it is matching on is non-empty (there exist values of this type). In safe code
-it is impossible to create an instance of an empty type, so empty match
-expressions are almost never desired. This error is typically fixed by adding
-one or more cases to the match expression.
-
-An example of an empty type is `enum Empty { }`. So, the following will work:
-
-```
-enum Empty {}
-
-fn foo(x: Empty) {
-    match x {
-        // empty
-    }
-}
-```
-
-However, this won't:
-
-```compile_fail
-enum Empty {}
-
-fn foo(x: Option<String>) {
-    match x {
-        // empty
-    }
-}
-```
-"##,
-
-E0003: r##"
-Not-a-Number (NaN) values cannot be compared for equality and hence can never
-match the input to a match expression. So, the following will not compile:
-
-```compile_fail
-const NAN: f32 = 0.0 / 0.0;
-
-let number = 0.1f32;
-
-match number {
-    NAN => { /* ... */ },
-    _ => {}
-}
-```
-
-To match against NaN values, you should instead use the `is_nan()` method in a
-guard, like so:
-
-```
-let number = 0.1f32;
-
-match number {
-    x if x.is_nan() => { /* ... */ }
-    _ => {}
-}
-```
-"##,
-
-E0004: r##"
-This error indicates that the compiler cannot guarantee a matching pattern for
-one or more possible inputs to a match expression. Guaranteed matches are
-required in order to assign values to match expressions, or alternatively,
-determine the flow of execution. Erroneous code example:
-
-```compile_fail
-enum Terminator {
-    HastaLaVistaBaby,
-    TalkToMyHand,
-}
-
-let x = Terminator::HastaLaVistaBaby;
-
-match x { // error: non-exhaustive patterns: `HastaLaVistaBaby` not covered
-    Terminator::TalkToMyHand => {}
-}
-```
-
-If you encounter this error you must alter your patterns so that every possible
-value of the input type is matched. For types with a small number of variants
-(like enums) you should probably cover all cases explicitly. Alternatively, the
-underscore `_` wildcard pattern can be added after all other patterns to match
-"anything else". Example:
-
-```
-enum Terminator {
-    HastaLaVistaBaby,
-    TalkToMyHand,
-}
-
-let x = Terminator::HastaLaVistaBaby;
-
-match x {
-    Terminator::TalkToMyHand => {}
-    Terminator::HastaLaVistaBaby => {}
-}
-
-// or:
-
-match x {
-    Terminator::TalkToMyHand => {}
-    _ => {}
-}
-```
-"##,
-
-E0005: r##"
-Patterns used to bind names must be irrefutable, that is, they must guarantee
-that a name will be extracted in all cases. Erroneous code example:
-
-```compile_fail
-let x = Some(1);
-let Some(y) = x;
-// error: refutable pattern in local binding: `None` not covered
-```
-
-If you encounter this error you probably need to use a `match` or `if let` to
-deal with the possibility of failure. Example:
-
-```compile_fail
-let x = Some(1);
-
-match x {
-    Some(y) => {
-        // do something
-    },
-    None => {}
-}
-
-// or:
-
-if let Some(y) = x {
-    // do something
-}
-```
-"##,
-
-E0007: r##"
-This error indicates that the bindings in a match arm would require a value to
-be moved into more than one location, thus violating unique ownership. Code
-like the following is invalid as it requires the entire `Option<String>` to be
-moved into a variable called `op_string` while simultaneously requiring the
-inner `String` to be moved into a variable called `s`.
-
-```compile_fail
-let x = Some("s".to_string());
-
-match x {
-    op_string @ Some(s) => {},
-    None => {},
-}
-```
-
-See also the error E0303.
-"##,
-
-E0008: r##"
-Names bound in match arms retain their type in pattern guards. As such, if a
-name is bound by move in a pattern, it should also be moved to wherever it is
-referenced in the pattern guard code. Doing so however would prevent the name
-from being available in the body of the match arm. Consider the following:
-
-```compile_fail
-match Some("hi".to_string()) {
-    Some(s) if s.len() == 0 => {}, // use s.
-    _ => {},
-}
-```
-
-The variable `s` has type `String`, and its use in the guard is as a variable of
-type `String`. The guard code effectively executes in a separate scope to the
-body of the arm, so the value would be moved into this anonymous scope and
-therefore become unavailable in the body of the arm. Although this example seems
-innocuous, the problem is most clear when considering functions that take their
-argument by value.
-
-```compile_fail
-match Some("hi".to_string()) {
-    Some(s) if { drop(s); false } => (),
-    Some(s) => {}, // use s.
-    _ => {},
-}
-```
-
-The value would be dropped in the guard then become unavailable not only in the
-body of that arm but also in all subsequent arms! The solution is to bind by
-reference when using guards or refactor the entire expression, perhaps by
-putting the condition inside the body of the arm.
-"##,
-
-E0009: r##"
-In a pattern, all values that don't implement the `Copy` trait have to be bound
-the same way. The goal here is to avoid binding simultaneously by-move and
-by-ref.
-
-This limitation may be removed in a future version of Rust.
-
-Erroneous code example:
-
-```compile_fail
-struct X { x: (), }
-
-let x = Some((X { x: () }, X { x: () }));
-match x {
-    Some((y, ref z)) => {},
-    None => panic!()
-}
-```
-
-You have two solutions:
-
-Solution #1: Bind the pattern's values the same way.
-
-```
-struct X { x: (), }
-
-let x = Some((X { x: () }, X { x: () }));
-match x {
-    Some((ref y, ref z)) => {},
-    // or Some((y, z)) => {}
-    None => panic!()
-}
-```
-
-Solution #2: Implement the `Copy` trait for the `X` structure.
-
-However, please keep in mind that the first solution should be preferred.
-
-```
-#[derive(Clone, Copy)]
-struct X { x: (), }
-
-let x = Some((X { x: () }, X { x: () }));
-match x {
-    Some((y, ref z)) => {},
-    None => panic!()
-}
-```
-"##,
-
 E0020: r##"
 This error indicates that an attempt was made to divide by zero (or take the
 remainder of a zero divisor) in a static or constant expression. Erroneous
@@ -762,128 +495,6 @@ attributes:
 See also https://doc.rust-lang.org/book/no-stdlib.html
 "##,
 
-E0158: r##"
-`const` and `static` mean different things. A `const` is a compile-time
-constant, an alias for a literal value. This property means you can match it
-directly within a pattern.
-
-The `static` keyword, on the other hand, guarantees a fixed location in memory.
-This does not always mean that the value is constant. For example, a global
-mutex can be declared `static` as well.
-
-If you want to match against a `static`, consider using a guard instead:
-
-```
-static FORTY_TWO: i32 = 42;
-
-match Some(42) {
-    Some(x) if x == FORTY_TWO => {}
-    _ => {}
-}
-```
-"##,
-
-E0162: r##"
-An if-let pattern attempts to match the pattern, and enters the body if the
-match was successful. If the match is irrefutable (when it cannot fail to
-match), use a regular `let`-binding instead. For instance:
-
-```compile_fail
-struct Irrefutable(i32);
-let irr = Irrefutable(0);
-
-// This fails to compile because the match is irrefutable.
-if let Irrefutable(x) = irr {
-    // This body will always be executed.
-    foo(x);
-}
-```
-
-Try this instead:
-
-```ignore
-struct Irrefutable(i32);
-let irr = Irrefutable(0);
-
-let Irrefutable(x) = irr;
-foo(x);
-```
-"##,
-
-E0165: r##"
-A while-let pattern attempts to match the pattern, and enters the body if the
-match was successful. If the match is irrefutable (when it cannot fail to
-match), use a regular `let`-binding inside a `loop` instead. For instance:
-
-```compile_fail
-struct Irrefutable(i32);
-let irr = Irrefutable(0);
-
-// This fails to compile because the match is irrefutable.
-while let Irrefutable(x) = irr {
-    ...
-}
-
-Try this instead:
-
-```
-struct Irrefutable(i32);
-let irr = Irrefutable(0);
-
-loop {
-    let Irrefutable(x) = irr;
-    ...
-}
-```
-"##,
-
-E0170: r##"
-Enum variants are qualified by default. For example, given this type:
-
-```
-enum Method {
-    GET,
-    POST,
-}
-```
-
-You would match it using:
-
-```
-enum Method {
-    GET,
-    POST,
-}
-
-let m = Method::GET;
-
-match m {
-    Method::GET => {},
-    Method::POST => {},
-}
-```
-
-If you don't qualify the names, the code will bind new variables named "GET" and
-"POST" instead. This behavior is likely not what you want, so `rustc` warns when
-that happens.
-
-Qualified names are good practice, and most code works well with them. But if
-you prefer them unqualified, you can import the variants into scope:
-
-```ignore
-use Method::*;
-enum Method { GET, POST }
-```
-
-If you want others to be able to import variants from your module directly, use
-`pub use`:
-
-```ignore
-pub use Method::*;
-enum Method { GET, POST }
-```
-"##,
-
 E0229: r##"
 An associated type binding was done outside of the type parameter declaration
 and `where` clause. Erroneous code example:
@@ -1573,135 +1184,6 @@ that the value provided is a positive integer between quotes, like so:
 ```
 "##,
 
-E0297: r##"
-Patterns used to bind names must be irrefutable. That is, they must guarantee
-that a name will be extracted in all cases. Instead of pattern matching the
-loop variable, consider using a `match` or `if let` inside the loop body. For
-instance:
-
-```compile_fail
-let xs : Vec<Option<i32>> = vec!(Some(1), None);
-
-// This fails because `None` is not covered.
-for Some(x) in xs {
-    // ...
-}
-```
-
-Match inside the loop instead:
-
-```
-let xs : Vec<Option<i32>> = vec!(Some(1), None);
-
-for item in xs {
-    match item {
-        Some(x) => {},
-        None => {},
-    }
-}
-```
-
-Or use `if let`:
-
-```
-let xs : Vec<Option<i32>> = vec!(Some(1), None);
-
-for item in xs {
-    if let Some(x) = item {
-        // ...
-    }
-}
-```
-"##,
-
-E0301: r##"
-Mutable borrows are not allowed in pattern guards, because matching cannot have
-side effects. Side effects could alter the matched object or the environment
-on which the match depends in such a way, that the match would not be
-exhaustive. For instance, the following would not match any arm if mutable
-borrows were allowed:
-
-```compile_fail
-match Some(()) {
-    None => { },
-    option if option.take().is_none() => {
-        /* impossible, option is `Some` */
-    },
-    Some(_) => { } // When the previous match failed, the option became `None`.
-}
-```
-"##,
-
-E0302: r##"
-Assignments are not allowed in pattern guards, because matching cannot have
-side effects. Side effects could alter the matched object or the environment
-on which the match depends in such a way, that the match would not be
-exhaustive. For instance, the following would not match any arm if assignments
-were allowed:
-
-```compile_fail
-match Some(()) {
-    None => { },
-    option if { option = None; false } { },
-    Some(_) => { } // When the previous match failed, the option became `None`.
-}
-```
-"##,
-
-E0303: r##"
-In certain cases it is possible for sub-bindings to violate memory safety.
-Updates to the borrow checker in a future version of Rust may remove this
-restriction, but for now patterns must be rewritten without sub-bindings.
-
-```ignore
-// Before.
-match Some("hi".to_string()) {
-    ref op_string_ref @ Some(s) => {},
-    None => {},
-}
-
-// After.
-match Some("hi".to_string()) {
-    Some(ref s) => {
-        let op_string_ref = &Some(s);
-        // ...
-    },
-    None => {},
-}
-```
-
-The `op_string_ref` binding has type `&Option<&String>` in both cases.
-
-See also https://github.com/rust-lang/rust/issues/14587
-"##,
-
-E0306: r##"
-In an array literal `[x; N]`, `N` is the number of elements in the array. This
-must be an unsigned integer. Erroneous code example:
-
-```compile_fail
-let x = [0i32; true]; // error: expected positive integer for repeat count,
-                      //        found boolean
-```
-
-Working example:
-
-```
-let x = [0i32; 2];
-```
-"##,
-
-E0307: r##"
-The length of an array is part of its type. For this reason, this length must
-be a compile-time constant. Erroneous code example:
-
-```compile_fail
-    let len = 10;
-    let x = [0i32; len]; // error: expected constant integer for repeat count,
-                         //        found variable
-```
-"##,
-
 E0308: r##"
 This error occurs when the compiler was unable to infer the concrete type of a
 variable. It can occur for several cases, the most common of which is a
@@ -1991,8 +1473,6 @@ register_diagnostics! {
     E0280, // requirement is not satisfied
     E0284, // cannot resolve type
 //  E0285, // overflow evaluation builtin bounds
-    E0298, // mismatched types between arms
-    E0299, // mismatched types between arms
 //  E0300, // unexpanded macro
 //  E0304, // expected signed integer constant
 //  E0305, // expected constant
@@ -2003,7 +1483,6 @@ register_diagnostics! {
     E0315, // cannot invoke closure outside of its lifetime
     E0316, // nested quantification of lifetimes
     E0453, // overruled by outer forbid
-    E0471, // constant evaluation error: ..
     E0473, // dereference of reference outside its lifetime
     E0474, // captured variable `..` does not outlive the enclosing closure
     E0475, // index of slice outside its lifetime
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index 1728bec5a8d..03a08231c74 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -91,8 +91,7 @@ pub mod lint;
 pub mod middle {
     pub mod astconv_util;
     pub mod expr_use_visitor; // STAGE0: increase glitch immunity
-    pub mod check_match;
-    pub mod const_eval;
+    pub mod const_val;
     pub mod const_qualif;
     pub mod cstore;
     pub mod dataflow;
diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs
new file mode 100644
index 00000000000..a939389c460
--- /dev/null
+++ b/src/librustc/middle/const_val.rs
@@ -0,0 +1,101 @@
+// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use syntax::parse::token::InternedString;
+use syntax::ast;
+use std::rc::Rc;
+use middle::def_id::DefId;
+use std::hash;
+use std::mem::transmute;
+use rustc_const_math::*;
+use self::ConstVal::*;
+
+#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
+pub enum ConstVal {
+    Float(f64),
+    Integral(ConstInt),
+    Str(InternedString),
+    ByteStr(Rc<Vec<u8>>),
+    Bool(bool),
+    Struct(ast::NodeId),
+    Tuple(ast::NodeId),
+    Function(DefId),
+    Array(ast::NodeId, u64),
+    Repeat(ast::NodeId, u64),
+    Char(char),
+    /// A value that only occurs in case `eval_const_expr` reported an error. You should never
+    /// handle this case. Its sole purpose is to allow more errors to be reported instead of
+    /// causing a fatal error.
+    Dummy,
+}
+
+impl hash::Hash for ConstVal {
+    fn hash<H: hash::Hasher>(&self, state: &mut H) {
+        match *self {
+            Float(a) => unsafe { transmute::<_,u64>(a) }.hash(state),
+            Integral(a) => a.hash(state),
+            Str(ref a) => a.hash(state),
+            ByteStr(ref a) => a.hash(state),
+            Bool(a) => a.hash(state),
+            Struct(a) => a.hash(state),
+            Tuple(a) => a.hash(state),
+            Function(a) => a.hash(state),
+            Array(a, n) => { a.hash(state); n.hash(state) },
+            Repeat(a, n) => { a.hash(state); n.hash(state) },
+            Char(c) => c.hash(state),
+            Dummy => ().hash(state),
+        }
+    }
+}
+
+/// 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 {
+    fn eq(&self, other: &ConstVal) -> bool {
+        match (self, other) {
+            (&Float(a), &Float(b)) => unsafe{transmute::<_,u64>(a) == transmute::<_,u64>(b)},
+            (&Integral(a), &Integral(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,
+            (&Function(a), &Function(b)) => a == b,
+            (&Array(a, an), &Array(b, bn)) => (a == b) && (an == bn),
+            (&Repeat(a, an), &Repeat(b, bn)) => (a == b) && (an == bn),
+            (&Char(a), &Char(b)) => a == b,
+            (&Dummy, &Dummy) => true, // FIXME: should this be false?
+            _ => false,
+        }
+    }
+}
+
+impl Eq for ConstVal { }
+
+impl ConstVal {
+    pub fn description(&self) -> &'static str {
+        match *self {
+            Float(_) => "float",
+            Integral(i) => i.description(),
+            Str(_) => "string literal",
+            ByteStr(_) => "byte string literal",
+            Bool(_) => "boolean",
+            Struct(_) => "struct",
+            Tuple(_) => "tuple",
+            Function(_) => "function definition",
+            Array(..) => "array",
+            Repeat(..) => "repeat",
+            Char(..) => "char",
+            Dummy => "dummy value",
+        }
+    }
+}
diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs
index d3b1a8d6c13..bc10d0c90ef 100644
--- a/src/librustc/mir/repr.rs
+++ b/src/librustc/mir/repr.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use graphviz::IntoCow;
-use middle::const_eval::ConstVal;
+use middle::const_val::ConstVal;
 use rustc_const_math::{ConstUsize, ConstInt};
 use middle::def_id::DefId;
 use ty::subst::Substs;
@@ -999,7 +999,7 @@ impl<'tcx> Debug for Literal<'tcx> {
 
 /// Write a `ConstVal` in a way closer to the original source code than the `Debug` output.
 fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
-    use middle::const_eval::ConstVal::*;
+    use middle::const_val::ConstVal::*;
     match *const_val {
         Float(f) => write!(fmt, "{:?}", f),
         Integral(n) => write!(fmt, "{}", n),
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index d11eea811cd..403c749fe4b 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use middle::const_eval::ConstVal;
+use middle::const_val::ConstVal;
 use middle::def_id::DefId;
 use ty::subst::Substs;
 use ty::{ClosureSubsts, FnOutput, Region, Ty};
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 970c807b36f..a3aa3f31cd1 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -11,8 +11,6 @@
 //! misc. type-system utilities too small to deserve their own file
 
 use back::svh::Svh;
-use middle::const_eval::{self, ConstVal, ErrKind};
-use middle::const_eval::EvalHint::UncheckedExprHint;
 use middle::def_id::DefId;
 use ty::subst;
 use infer;
@@ -269,41 +267,6 @@ impl<'tcx> TyCtxt<'tcx> {
         (a, b)
     }
 
-    /// Returns the repeat count for a repeating vector expression.
-    pub fn eval_repeat_count(&self, count_expr: &hir::Expr) -> usize {
-        let hint = UncheckedExprHint(self.types.usize);
-        match const_eval::eval_const_expr_partial(self, count_expr, hint, None) {
-            Ok(ConstVal::Integral(ConstInt::Usize(count))) => {
-                let val = count.as_u64(self.sess.target.uint_type);
-                assert_eq!(val as usize as u64, val);
-                val as usize
-            },
-            Ok(const_val) => {
-                span_err!(self.sess, count_expr.span, E0306,
-                          "expected positive integer for repeat count, found {}",
-                          const_val.description());
-                0
-            }
-            Err(err) => {
-                let err_msg = match count_expr.node {
-                    hir::ExprPath(None, hir::Path {
-                        global: false,
-                        ref segments,
-                        ..
-                    }) if segments.len() == 1 =>
-                        format!("found variable"),
-                    _ => match err.kind {
-                        ErrKind::MiscCatchAll => format!("but found {}", err.description()),
-                        _ => format!("but {}", err.description())
-                    }
-                };
-                span_err!(self.sess, count_expr.span, E0307,
-                    "expected constant integer for repeat count, {}", err_msg);
-                0
-            }
-        }
-    }
-
     /// Given a set of predicates that apply to an object type, returns
     /// the region bounds that the (erased) `Self` type must
     /// outlive. Precisely *because* the `Self` type is erased, the
diff --git a/src/librustc_const_eval/Cargo.toml b/src/librustc_const_eval/Cargo.toml
new file mode 100644
index 00000000000..f38c60cd1fa
--- /dev/null
+++ b/src/librustc_const_eval/Cargo.toml
@@ -0,0 +1,19 @@
+[package]
+authors = ["The Rust Project Developers"]
+name = "rustc_const_eval"
+version = "0.0.0"
+
+[lib]
+name = "rustc_const_eval"
+path = "lib.rs"
+crate-type = ["dylib"]
+
+[dependencies]
+log = { path = "../liblog" }
+serialize = { path = "../libserialize" }
+rustc = { path = "../librustc" }
+rustc_front = { path = "../librustc_front" }
+rustc_back = { path = "../librustc_back" }
+rustc_const_math = { path = "../librustc_const_math" }
+syntax = { path = "../libsyntax" }
+graphviz = { path = "../libgraphviz" }
diff --git a/src/librustc/middle/check_match.rs b/src/librustc_const_eval/check_match.rs
index 79e4b7c0901..f00df1f671f 100644
--- a/src/librustc/middle/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -1,4 +1,4 @@
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -12,22 +12,22 @@ pub use self::Constructor::*;
 use self::Usefulness::*;
 use self::WitnessPreference::*;
 
-use dep_graph::DepNode;
-use middle::const_eval::{compare_const_vals, ConstVal};
-use middle::const_eval::{eval_const_expr, eval_const_expr_partial};
-use middle::const_eval::{const_expr_to_pat, lookup_const_by_id};
-use middle::const_eval::EvalHint::ExprTypeChecked;
-use middle::def::*;
-use middle::def_id::{DefId};
-use middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor};
-use middle::expr_use_visitor::{LoanCause, MutateMode};
-use middle::expr_use_visitor as euv;
-use infer;
-use middle::mem_categorization::{cmt};
-use middle::pat_util::*;
-use traits::ProjectionMode;
-use ty::*;
-use ty;
+use rustc::dep_graph::DepNode;
+use rustc::middle::const_val::ConstVal;
+use ::{eval_const_expr, eval_const_expr_partial, compare_const_vals};
+use ::{const_expr_to_pat, lookup_const_by_id};
+use ::EvalHint::ExprTypeChecked;
+use rustc::middle::def::*;
+use rustc::middle::def_id::{DefId};
+use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor};
+use rustc::middle::expr_use_visitor::{LoanCause, MutateMode};
+use rustc::middle::expr_use_visitor as euv;
+use rustc::infer;
+use rustc::middle::mem_categorization::{cmt};
+use rustc::middle::pat_util::*;
+use rustc::traits::ProjectionMode;
+use rustc::ty::*;
+use rustc::ty;
 use std::cmp::Ordering;
 use std::fmt;
 use std::iter::{FromIterator, IntoIterator, repeat};
@@ -44,7 +44,7 @@ use syntax::codemap::{Span, Spanned, DUMMY_SP};
 use rustc_front::fold::{Folder, noop_fold_pat};
 use rustc_front::print::pprust::pat_to_string;
 use syntax::ptr::P;
-use util::nodemap::FnvHashMap;
+use rustc::util::nodemap::FnvHashMap;
 
 pub const DUMMY_WILD_PAT: &'static Pat = &Pat {
     id: DUMMY_NODE_ID,
@@ -546,7 +546,7 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor,
         ty::TyTuple(_) => PatKind::Tup(pats.collect()),
 
         ty::TyEnum(adt, _) | ty::TyStruct(adt, _)  => {
-            let v = adt.variant_of_ctor(ctor);
+            let v = ctor.variant_for_adt(adt);
             match v.kind() {
                 VariantKind::Struct => {
                     let field_pats: hir::HirVec<_> = v.fields.iter()
@@ -617,13 +617,13 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor,
     })
 }
 
-impl<'tcx, 'container> ty::AdtDefData<'tcx, 'container> {
-    fn variant_of_ctor(&self,
-                       ctor: &Constructor)
-                       -> &VariantDefData<'tcx, 'container> {
-        match ctor {
-            &Variant(vid) => self.variant_with_id(vid),
-            _ => self.struct_variant()
+impl Constructor {
+    fn variant_for_adt<'tcx, 'container, 'a>(&self,
+                                             adt: &'a ty::AdtDefData<'tcx, 'container>)
+                                             -> &'a VariantDefData<'tcx, 'container> {
+        match self {
+            &Variant(vid) => adt.variant_with_id(vid),
+            _ => adt.struct_variant()
         }
     }
 }
@@ -843,7 +843,7 @@ pub fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> us
             _ => 1
         },
         ty::TyEnum(adt, _) | ty::TyStruct(adt, _) => {
-            adt.variant_of_ctor(ctor).fields.len()
+            ctor.variant_for_adt(adt).fields.len()
         }
         ty::TyArray(_, n) => n,
         _ => 0
@@ -924,7 +924,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
         PatKind::Struct(_, ref pattern_fields, _) => {
             let def = cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def();
             let adt = cx.tcx.node_id_to_type(pat_id).ty_adt_def().unwrap();
-            let variant = adt.variant_of_ctor(constructor);
+            let variant = constructor.variant_for_adt(adt);
             let def_variant = adt.variant_of_def(def);
             if variant.did == def_variant.did {
                 Some(variant.fields.iter().map(|sf| {
diff --git a/src/librustc_const_eval/diagnostics.rs b/src/librustc_const_eval/diagnostics.rs
new file mode 100644
index 00000000000..4f5176f6b0b
--- /dev/null
+++ b/src/librustc_const_eval/diagnostics.rs
@@ -0,0 +1,545 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(non_snake_case)]
+
+// Error messages for EXXXX errors.
+// Each message should start and end with a new line, and be wrapped to 80 characters.
+// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
+register_long_diagnostics! {
+
+E0001: r##"
+This error suggests that the expression arm corresponding to the noted pattern
+will never be reached as for all possible values of the expression being
+matched, one of the preceding patterns will match.
+
+This means that perhaps some of the preceding patterns are too general, this
+one is too specific or the ordering is incorrect.
+
+For example, the following `match` block has too many arms:
+
+```compile_fail
+match foo {
+    Some(bar) => {/* ... */}
+    None => {/* ... */}
+    _ => {/* ... */} // All possible cases have already been handled
+}
+```
+
+`match` blocks have their patterns matched in order, so, for example, putting
+a wildcard arm above a more specific arm will make the latter arm irrelevant.
+
+Ensure the ordering of the match arm is correct and remove any superfluous
+arms.
+"##,
+
+E0002: r##"
+This error indicates that an empty match expression is invalid because the type
+it is matching on is non-empty (there exist values of this type). In safe code
+it is impossible to create an instance of an empty type, so empty match
+expressions are almost never desired. This error is typically fixed by adding
+one or more cases to the match expression.
+
+An example of an empty type is `enum Empty { }`. So, the following will work:
+
+```
+enum Empty {}
+
+fn foo(x: Empty) {
+    match x {
+        // empty
+    }
+}
+```
+
+However, this won't:
+
+```compile_fail
+enum Empty {}
+
+fn foo(x: Option<String>) {
+    match x {
+        // empty
+    }
+}
+```
+"##,
+
+
+E0003: r##"
+Not-a-Number (NaN) values cannot be compared for equality and hence can never
+match the input to a match expression. So, the following will not compile:
+
+```compile_fail
+const NAN: f32 = 0.0 / 0.0;
+
+let number = 0.1f32;
+
+match number {
+    NAN => { /* ... */ },
+    _ => {}
+}
+```
+
+To match against NaN values, you should instead use the `is_nan()` method in a
+guard, like so:
+
+```
+let number = 0.1f32;
+
+match number {
+    x if x.is_nan() => { /* ... */ }
+    _ => {}
+}
+```
+"##,
+
+
+E0004: r##"
+This error indicates that the compiler cannot guarantee a matching pattern for
+one or more possible inputs to a match expression. Guaranteed matches are
+required in order to assign values to match expressions, or alternatively,
+determine the flow of execution. Erroneous code example:
+
+```compile_fail
+enum Terminator {
+    HastaLaVistaBaby,
+    TalkToMyHand,
+}
+
+let x = Terminator::HastaLaVistaBaby;
+
+match x { // error: non-exhaustive patterns: `HastaLaVistaBaby` not covered
+    Terminator::TalkToMyHand => {}
+}
+```
+
+If you encounter this error you must alter your patterns so that every possible
+value of the input type is matched. For types with a small number of variants
+(like enums) you should probably cover all cases explicitly. Alternatively, the
+underscore `_` wildcard pattern can be added after all other patterns to match
+"anything else". Example:
+
+```
+enum Terminator {
+    HastaLaVistaBaby,
+    TalkToMyHand,
+}
+
+let x = Terminator::HastaLaVistaBaby;
+
+match x {
+    Terminator::TalkToMyHand => {}
+    Terminator::HastaLaVistaBaby => {}
+}
+
+// or:
+
+match x {
+    Terminator::TalkToMyHand => {}
+    _ => {}
+}
+```
+"##,
+
+E0005: r##"
+Patterns used to bind names must be irrefutable, that is, they must guarantee
+that a name will be extracted in all cases. Erroneous code example:
+
+```compile_fail
+let x = Some(1);
+let Some(y) = x;
+// error: refutable pattern in local binding: `None` not covered
+```
+
+If you encounter this error you probably need to use a `match` or `if let` to
+deal with the possibility of failure. Example:
+
+```compile_fail
+let x = Some(1);
+
+match x {
+    Some(y) => {
+        // do something
+    },
+    None => {}
+}
+
+// or:
+
+if let Some(y) = x {
+    // do something
+}
+```
+"##,
+
+E0007: r##"
+This error indicates that the bindings in a match arm would require a value to
+be moved into more than one location, thus violating unique ownership. Code
+like the following is invalid as it requires the entire `Option<String>` to be
+moved into a variable called `op_string` while simultaneously requiring the
+inner `String` to be moved into a variable called `s`.
+
+```compile_fail
+let x = Some("s".to_string());
+
+match x {
+    op_string @ Some(s) => {},
+    None => {},
+}
+```
+
+See also the error E0303.
+"##,
+
+E0008: r##"
+Names bound in match arms retain their type in pattern guards. As such, if a
+name is bound by move in a pattern, it should also be moved to wherever it is
+referenced in the pattern guard code. Doing so however would prevent the name
+from being available in the body of the match arm. Consider the following:
+
+```compile_fail
+match Some("hi".to_string()) {
+    Some(s) if s.len() == 0 => {}, // use s.
+    _ => {},
+}
+```
+
+The variable `s` has type `String`, and its use in the guard is as a variable of
+type `String`. The guard code effectively executes in a separate scope to the
+body of the arm, so the value would be moved into this anonymous scope and
+therefore become unavailable in the body of the arm. Although this example seems
+innocuous, the problem is most clear when considering functions that take their
+argument by value.
+
+```compile_fail
+match Some("hi".to_string()) {
+    Some(s) if { drop(s); false } => (),
+    Some(s) => {}, // use s.
+    _ => {},
+}
+```
+
+The value would be dropped in the guard then become unavailable not only in the
+body of that arm but also in all subsequent arms! The solution is to bind by
+reference when using guards or refactor the entire expression, perhaps by
+putting the condition inside the body of the arm.
+"##,
+
+E0009: r##"
+In a pattern, all values that don't implement the `Copy` trait have to be bound
+the same way. The goal here is to avoid binding simultaneously by-move and
+by-ref.
+
+This limitation may be removed in a future version of Rust.
+
+Erroneous code example:
+
+```compile_fail
+struct X { x: (), }
+
+let x = Some((X { x: () }, X { x: () }));
+match x {
+    Some((y, ref z)) => {},
+    None => panic!()
+}
+```
+
+You have two solutions:
+
+Solution #1: Bind the pattern's values the same way.
+
+```
+struct X { x: (), }
+
+let x = Some((X { x: () }, X { x: () }));
+match x {
+    Some((ref y, ref z)) => {},
+    // or Some((y, z)) => {}
+    None => panic!()
+}
+```
+
+Solution #2: Implement the `Copy` trait for the `X` structure.
+
+However, please keep in mind that the first solution should be preferred.
+
+```
+#[derive(Clone, Copy)]
+struct X { x: (), }
+
+let x = Some((X { x: () }, X { x: () }));
+match x {
+    Some((y, ref z)) => {},
+    None => panic!()
+}
+```
+"##,
+
+E0158: r##"
+`const` and `static` mean different things. A `const` is a compile-time
+constant, an alias for a literal value. This property means you can match it
+directly within a pattern.
+
+The `static` keyword, on the other hand, guarantees a fixed location in memory.
+This does not always mean that the value is constant. For example, a global
+mutex can be declared `static` as well.
+
+If you want to match against a `static`, consider using a guard instead:
+
+```
+static FORTY_TWO: i32 = 42;
+
+match Some(42) {
+    Some(x) if x == FORTY_TWO => {}
+    _ => {}
+}
+```
+"##,
+
+E0162: r##"
+An if-let pattern attempts to match the pattern, and enters the body if the
+match was successful. If the match is irrefutable (when it cannot fail to
+match), use a regular `let`-binding instead. For instance:
+
+```compile_fail
+struct Irrefutable(i32);
+let irr = Irrefutable(0);
+
+// This fails to compile because the match is irrefutable.
+if let Irrefutable(x) = irr {
+    // This body will always be executed.
+    foo(x);
+}
+```
+
+Try this instead:
+
+```ignore
+struct Irrefutable(i32);
+let irr = Irrefutable(0);
+
+let Irrefutable(x) = irr;
+foo(x);
+```
+"##,
+
+E0165: r##"
+A while-let pattern attempts to match the pattern, and enters the body if the
+match was successful. If the match is irrefutable (when it cannot fail to
+match), use a regular `let`-binding inside a `loop` instead. For instance:
+
+```compile_fail
+struct Irrefutable(i32);
+let irr = Irrefutable(0);
+
+// This fails to compile because the match is irrefutable.
+while let Irrefutable(x) = irr {
+    ...
+}
+
+Try this instead:
+
+```
+struct Irrefutable(i32);
+let irr = Irrefutable(0);
+
+loop {
+    let Irrefutable(x) = irr;
+    ...
+}
+```
+"##,
+
+E0170: r##"
+Enum variants are qualified by default. For example, given this type:
+
+```
+enum Method {
+    GET,
+    POST,
+}
+```
+
+You would match it using:
+
+```
+enum Method {
+    GET,
+    POST,
+}
+
+let m = Method::GET;
+
+match m {
+    Method::GET => {},
+    Method::POST => {},
+}
+```
+
+If you don't qualify the names, the code will bind new variables named "GET" and
+"POST" instead. This behavior is likely not what you want, so `rustc` warns when
+that happens.
+
+Qualified names are good practice, and most code works well with them. But if
+you prefer them unqualified, you can import the variants into scope:
+
+```ignore
+use Method::*;
+enum Method { GET, POST }
+```
+
+If you want others to be able to import variants from your module directly, use
+`pub use`:
+
+```ignore
+pub use Method::*;
+enum Method { GET, POST }
+```
+"##,
+
+
+E0297: r##"
+Patterns used to bind names must be irrefutable. That is, they must guarantee
+that a name will be extracted in all cases. Instead of pattern matching the
+loop variable, consider using a `match` or `if let` inside the loop body. For
+instance:
+
+```compile_fail
+let xs : Vec<Option<i32>> = vec!(Some(1), None);
+
+// This fails because `None` is not covered.
+for Some(x) in xs {
+    // ...
+}
+```
+
+Match inside the loop instead:
+
+```
+let xs : Vec<Option<i32>> = vec!(Some(1), None);
+
+for item in xs {
+    match item {
+        Some(x) => {},
+        None => {},
+    }
+}
+```
+
+Or use `if let`:
+
+```
+let xs : Vec<Option<i32>> = vec!(Some(1), None);
+
+for item in xs {
+    if let Some(x) = item {
+        // ...
+    }
+}
+```
+"##,
+
+E0301: r##"
+Mutable borrows are not allowed in pattern guards, because matching cannot have
+side effects. Side effects could alter the matched object or the environment
+on which the match depends in such a way, that the match would not be
+exhaustive. For instance, the following would not match any arm if mutable
+borrows were allowed:
+
+```compile_fail
+match Some(()) {
+    None => { },
+    option if option.take().is_none() => {
+        /* impossible, option is `Some` */
+    },
+    Some(_) => { } // When the previous match failed, the option became `None`.
+}
+```
+"##,
+
+E0302: r##"
+Assignments are not allowed in pattern guards, because matching cannot have
+side effects. Side effects could alter the matched object or the environment
+on which the match depends in such a way, that the match would not be
+exhaustive. For instance, the following would not match any arm if assignments
+were allowed:
+
+```compile_fail
+match Some(()) {
+    None => { },
+    option if { option = None; false } { },
+    Some(_) => { } // When the previous match failed, the option became `None`.
+}
+```
+"##,
+
+E0303: r##"
+In certain cases it is possible for sub-bindings to violate memory safety.
+Updates to the borrow checker in a future version of Rust may remove this
+restriction, but for now patterns must be rewritten without sub-bindings.
+
+```ignore
+// Before.
+match Some("hi".to_string()) {
+    ref op_string_ref @ Some(s) => {},
+    None => {},
+}
+
+// After.
+match Some("hi".to_string()) {
+    Some(ref s) => {
+        let op_string_ref = &Some(s);
+        // ...
+    },
+    None => {},
+}
+```
+
+The `op_string_ref` binding has type `&Option<&String>` in both cases.
+
+See also https://github.com/rust-lang/rust/issues/14587
+"##,
+
+E0306: r##"
+In an array literal `[x; N]`, `N` is the number of elements in the array. This
+must be an unsigned integer. Erroneous code example:
+
+```compile_fail
+let x = [0i32; true]; // error: expected positive integer for repeat count,
+                      //        found boolean
+```
+
+Working example:
+
+```
+let x = [0i32; 2];
+```
+"##,
+
+E0307: r##"
+The length of an array is part of its type. For this reason, this length must
+be a compile-time constant. Erroneous code example:
+
+```compile_fail
+    let len = 10;
+    let x = [0i32; len]; // error: expected constant integer for repeat count,
+                         //        found variable
+```
+"##,
+
+}
+
+
+register_diagnostics! {
+E0298, // mismatched types between arms
+E0299, // mismatched types between arms
+E0471, // constant evaluation error: ..
+}
diff --git a/src/librustc/middle/const_eval.rs b/src/librustc_const_eval/eval.rs
index f685e4c0e18..a36d0b3fcff 100644
--- a/src/librustc/middle/const_eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -1,4 +1,4 @@
-// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -10,23 +10,24 @@
 
 //#![allow(non_camel_case_types)]
 
-use self::ConstVal::*;
+use rustc::middle::const_val::ConstVal::*;
+use rustc::middle::const_val::ConstVal;
 use self::ErrKind::*;
 use self::EvalHint::*;
 
-use front::map as ast_map;
-use front::map::blocks::FnLikeNode;
-use lint;
-use middle::cstore::{self, CrateStore, InlinedItem};
-use {infer, traits};
-use middle::def::Def;
-use middle::def_id::DefId;
-use middle::pat_util::def_to_path;
-use ty::{self, subst, Ty, TyCtxt};
-use ty::util::IntTypeExt;
-use traits::ProjectionMode;
-use middle::astconv_util::ast_ty_to_prim_ty;
-use util::nodemap::NodeMap;
+use rustc::front::map as ast_map;
+use rustc::front::map::blocks::FnLikeNode;
+use rustc::middle::cstore::{self, CrateStore, InlinedItem};
+use rustc::{infer, traits};
+use rustc::middle::def::Def;
+use rustc::middle::def_id::DefId;
+use rustc::middle::pat_util::def_to_path;
+use rustc::ty::{self, Ty, TyCtxt, subst};
+use rustc::ty::util::IntTypeExt;
+use rustc::traits::ProjectionMode;
+use rustc::middle::astconv_util::ast_ty_to_prim_ty;
+use rustc::util::nodemap::NodeMap;
+use rustc::lint;
 
 use graphviz::IntoCow;
 use syntax::ast;
@@ -34,7 +35,6 @@ use rustc_front::hir::{Expr, PatKind};
 use rustc_front::hir;
 use rustc_front::intravisit::FnKind;
 use syntax::codemap::Span;
-use syntax::parse::token::InternedString;
 use syntax::ptr::P;
 use syntax::codemap;
 use syntax::attr::IntType;
@@ -42,9 +42,6 @@ use syntax::attr::IntType;
 use std::borrow::Cow;
 use std::cmp::Ordering;
 use std::collections::hash_map::Entry::Vacant;
-use std::hash;
-use std::mem::transmute;
-use std::rc::Rc;
 
 use rustc_const_math::*;
 
@@ -241,89 +238,6 @@ pub fn lookup_const_fn_by_id<'tcx>(tcx: &TyCtxt<'tcx>, def_id: DefId)
     }
 }
 
-#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
-pub enum ConstVal {
-    Float(f64),
-    Integral(ConstInt),
-    Str(InternedString),
-    ByteStr(Rc<Vec<u8>>),
-    Bool(bool),
-    Struct(ast::NodeId),
-    Tuple(ast::NodeId),
-    Function(DefId),
-    Array(ast::NodeId, u64),
-    Repeat(ast::NodeId, u64),
-    Char(char),
-    /// A value that only occurs in case `eval_const_expr` reported an error. You should never
-    /// handle this case. Its sole purpose is to allow more errors to be reported instead of
-    /// causing a fatal error.
-    Dummy,
-}
-
-impl hash::Hash for ConstVal {
-    fn hash<H: hash::Hasher>(&self, state: &mut H) {
-        match *self {
-            Float(a) => unsafe { transmute::<_,u64>(a) }.hash(state),
-            Integral(a) => a.hash(state),
-            Str(ref a) => a.hash(state),
-            ByteStr(ref a) => a.hash(state),
-            Bool(a) => a.hash(state),
-            Struct(a) => a.hash(state),
-            Tuple(a) => a.hash(state),
-            Function(a) => a.hash(state),
-            Array(a, n) => { a.hash(state); n.hash(state) },
-            Repeat(a, n) => { a.hash(state); n.hash(state) },
-            Char(c) => c.hash(state),
-            Dummy => ().hash(state),
-        }
-    }
-}
-
-/// 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 {
-    fn eq(&self, other: &ConstVal) -> bool {
-        match (self, other) {
-            (&Float(a), &Float(b)) => unsafe{transmute::<_,u64>(a) == transmute::<_,u64>(b)},
-            (&Integral(a), &Integral(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,
-            (&Function(a), &Function(b)) => a == b,
-            (&Array(a, an), &Array(b, bn)) => (a == b) && (an == bn),
-            (&Repeat(a, an), &Repeat(b, bn)) => (a == b) && (an == bn),
-            (&Char(a), &Char(b)) => a == b,
-            (&Dummy, &Dummy) => true, // FIXME: should this be false?
-            _ => false,
-        }
-    }
-}
-
-impl Eq for ConstVal { }
-
-impl ConstVal {
-    pub fn description(&self) -> &'static str {
-        match *self {
-            Float(_) => "float",
-            Integral(i) => i.description(),
-            Str(_) => "string literal",
-            ByteStr(_) => "byte string literal",
-            Bool(_) => "boolean",
-            Struct(_) => "struct",
-            Tuple(_) => "tuple",
-            Function(_) => "function definition",
-            Array(..) => "array",
-            Repeat(..) => "repeat",
-            Char(..) => "char",
-            Dummy => "dummy value",
-        }
-    }
-}
-
 pub fn const_expr_to_pat(tcx: &ty::TyCtxt, expr: &Expr, pat_id: ast::NodeId, span: Span)
                          -> Result<P<hir::Pat>, DefId> {
     let pat_ty = tcx.expr_ty(expr);
@@ -352,7 +266,6 @@ pub fn const_expr_to_pat(tcx: &ty::TyCtxt, expr: &Expr, pat_id: ast::NodeId, spa
         }
         _ => { }
     }
-
     let pat = match expr.node {
         hir::ExprTup(ref exprs) =>
             PatKind::Tup(try!(exprs.iter()
@@ -1275,3 +1188,39 @@ pub fn compare_lit_exprs<'tcx>(tcx: &TyCtxt<'tcx>,
     };
     compare_const_vals(&a, &b)
 }
+
+
+/// Returns the repeat count for a repeating vector expression.
+pub fn eval_repeat_count(tcx: &TyCtxt, count_expr: &hir::Expr) -> usize {
+    let hint = UncheckedExprHint(tcx.types.usize);
+    match eval_const_expr_partial(tcx, count_expr, hint, None) {
+        Ok(Integral(Usize(count))) => {
+            let val = count.as_u64(tcx.sess.target.uint_type);
+            assert_eq!(val as usize as u64, val);
+            val as usize
+        },
+        Ok(const_val) => {
+            span_err!(tcx.sess, count_expr.span, E0306,
+                      "expected positive integer for repeat count, found {}",
+                      const_val.description());
+            0
+        }
+        Err(err) => {
+            let err_msg = match count_expr.node {
+                hir::ExprPath(None, hir::Path {
+                    global: false,
+                    ref segments,
+                    ..
+                }) if segments.len() == 1 =>
+                    format!("found variable"),
+                _ => match err.kind {
+                    MiscCatchAll => format!("but found {}", err.description()),
+                    _ => format!("but {}", err.description())
+                }
+            };
+            span_err!(tcx.sess, count_expr.span, E0307,
+                "expected constant integer for repeat count, {}", err_msg);
+            0
+        }
+    }
+}
diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs
new file mode 100644
index 00000000000..558ae71756b
--- /dev/null
+++ b/src/librustc_const_eval/lib.rs
@@ -0,0 +1,53 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! constant evaluation on the HIR and code to validate patterns/matches
+//!
+//! # Note
+//!
+//! This API is completely unstable and subject to change.
+
+#![crate_name = "rustc_const_eval"]
+#![unstable(feature = "rustc_private", issue = "27812")]
+#![crate_type = "dylib"]
+#![crate_type = "rlib"]
+#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
+      html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
+      html_root_url = "https://doc.rust-lang.org/nightly/")]
+
+
+#![feature(rustc_private)]
+#![feature(staged_api)]
+#![feature(rustc_diagnostic_macros)]
+#![feature(slice_patterns)]
+#![feature(iter_arith)]
+#![feature(question_mark)]
+
+#[macro_use] extern crate syntax;
+#[macro_use] extern crate log;
+extern crate rustc;
+extern crate rustc_front;
+extern crate rustc_back;
+extern crate rustc_const_math;
+extern crate graphviz;
+
+extern crate serialize as rustc_serialize; // used by deriving
+
+// NB: This module needs to be declared first so diagnostics are
+// registered before they are used.
+pub mod diagnostics;
+
+mod eval;
+pub mod check_match;
+
+pub use eval::*;
+
+// Build the diagnostics array at the end so that the metadata includes error use sites.
+__build_diagnostic_array! { librustc_const_eval, DIAGNOSTICS }
diff --git a/src/librustc_const_math/int.rs b/src/librustc_const_math/int.rs
index 7576a984bec..658d4d9a6d2 100644
--- a/src/librustc_const_math/int.rs
+++ b/src/librustc_const_math/int.rs
@@ -326,7 +326,7 @@ macro_rules! impl_binop {
         impl ::std::ops::$op for ConstInt {
             type Output = Result<Self, ConstMathErr>;
             fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
-                match try!(self.infer(rhs)) {
+                match self.infer(rhs)? {
                     (I8(a), I8(b)) => a.$checked_func(b).map(I8),
                     (I16(a), I16(b)) => a.$checked_func(b).map(I16),
                     (I32(a), I32(b)) => a.$checked_func(b).map(I32),
@@ -353,7 +353,7 @@ macro_rules! derive_binop {
         impl ::std::ops::$op for ConstInt {
             type Output = Result<Self, ConstMathErr>;
             fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
-                match try!(self.infer(rhs)) {
+                match self.infer(rhs)? {
                     (I8(a), I8(b)) => Ok(I8(a.$func(b))),
                     (I16(a), I16(b)) => Ok(I16(a.$func(b))),
                     (I32(a), I32(b)) => Ok(I32(a.$func(b))),
diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml
index c8c51793444..803b919058d 100644
--- a/src/librustc_driver/Cargo.toml
+++ b/src/librustc_driver/Cargo.toml
@@ -17,6 +17,7 @@ log = { path = "../liblog" }
 rustc = { path = "../librustc" }
 rustc_back = { path = "../librustc_back" }
 rustc_borrowck = { path = "../librustc_borrowck" }
+rustc_const_eval = { path = "../librustc_const_eval" }
 rustc_front = { path = "../librustc_front" }
 rustc_lint = { path = "../librustc_lint" }
 rustc_llvm = { path = "../librustc_llvm" }
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 468dc7b12c1..61f8c9bcc4f 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -38,6 +38,7 @@ use rustc_plugin as plugin;
 use rustc_front::hir;
 use rustc_front::lowering::{lower_crate, LoweringContext};
 use rustc_passes::{no_asm, loops, consts, const_fn, rvalues, static_recursion};
+use rustc_const_eval::check_match;
 use super::Compilation;
 
 use serialize::json;
@@ -851,7 +852,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
 
         time(time_passes,
              "match checking",
-             || middle::check_match::check_crate(tcx));
+             || check_match::check_crate(tcx));
 
         // this must run before MIR dump, because
         // "not all control paths return a value" is reported here.
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 057a34c27b1..516c55e1020 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -40,6 +40,7 @@ extern crate libc;
 extern crate rustc;
 extern crate rustc_back;
 extern crate rustc_borrowck;
+extern crate rustc_const_eval;
 extern crate rustc_passes;
 extern crate rustc_front;
 extern crate rustc_lint;
@@ -1090,6 +1091,7 @@ pub fn diagnostics_registry() -> diagnostics::registry::Registry {
     all_errors.extend_from_slice(&rustc_resolve::DIAGNOSTICS);
     all_errors.extend_from_slice(&rustc_privacy::DIAGNOSTICS);
     all_errors.extend_from_slice(&rustc_trans::DIAGNOSTICS);
+    all_errors.extend_from_slice(&rustc_const_eval::DIAGNOSTICS);
 
     Registry::new(&all_errors)
 }
diff --git a/src/librustc_lint/Cargo.toml b/src/librustc_lint/Cargo.toml
index 33443957d1b..4821a723279 100644
--- a/src/librustc_lint/Cargo.toml
+++ b/src/librustc_lint/Cargo.toml
@@ -12,5 +12,6 @@ crate-type = ["dylib"]
 log = { path = "../liblog" }
 rustc = { path = "../librustc" }
 rustc_back = { path = "../librustc_back" }
+rustc_const_eval = { path = "../librustc_const_eval" }
 rustc_front = { path = "../librustc_front" }
 syntax = { path = "../libsyntax" }
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index 9ed21117ceb..6e3a961caca 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -46,6 +46,7 @@ extern crate rustc;
 extern crate log;
 extern crate rustc_front;
 extern crate rustc_back;
+extern crate rustc_const_eval;
 
 pub use rustc::lint as lint;
 pub use rustc::middle as middle;
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index 6322f592573..80733bccf8e 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -14,8 +14,9 @@ use middle::def_id::DefId;
 use rustc::infer;
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, Ty, TyCtxt};
-use middle::const_eval::{eval_const_expr_partial, ConstVal};
-use middle::const_eval::EvalHint::ExprTypeChecked;
+use middle::const_val::ConstVal;
+use rustc_const_eval::eval_const_expr_partial;
+use rustc_const_eval::EvalHint::ExprTypeChecked;
 use util::nodemap::{FnvHashSet};
 use lint::{LateContext, LintContext, LintArray};
 use lint::{LintPass, LateLintPass};
diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml
index 35c29e2cf2d..f136618b1c9 100644
--- a/src/librustc_mir/Cargo.toml
+++ b/src/librustc_mir/Cargo.toml
@@ -13,6 +13,7 @@ graphviz = { path = "../libgraphviz" }
 log = { path = "../liblog" }
 rustc = { path = "../librustc" }
 rustc_back = { path = "../librustc_back" }
+rustc_const_eval = { path = "../librustc_const_eval" }
 rustc_const_math = { path = "../librustc_const_math" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_front = { path = "../librustc_front" }
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index 581e8e35ee8..68563197014 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -15,7 +15,7 @@
 
 use build::{BlockAnd, BlockAndExtension, Builder};
 use rustc_data_structures::fnv::FnvHashMap;
-use rustc::middle::const_eval::ConstVal;
+use rustc::middle::const_val::ConstVal;
 use rustc::ty::{AdtDef, Ty};
 use rustc::mir::repr::*;
 use hair::*;
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index 5a1c3739ef5..dc70cf4ffb9 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -19,7 +19,7 @@ use build::Builder;
 use build::matches::{Candidate, MatchPair, Test, TestKind};
 use hair::*;
 use rustc_data_structures::fnv::FnvHashMap;
-use rustc::middle::const_eval::ConstVal;
+use rustc::middle::const_val::ConstVal;
 use rustc::ty::{self, Ty};
 use rustc::mir::repr::*;
 use syntax::codemap::Span;
diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs
index ffaf02bbfee..e3093eab22b 100644
--- a/src/librustc_mir/build/scope.rs
+++ b/src/librustc_mir/build/scope.rs
@@ -94,7 +94,7 @@ use rustc::ty::{self, Ty, TyCtxt};
 use rustc::mir::repr::*;
 use syntax::codemap::{Span, DUMMY_SP};
 use syntax::parse::token::intern_and_get_ident;
-use rustc::middle::const_eval::ConstVal;
+use rustc::middle::const_val::ConstVal;
 use rustc_const_math::ConstInt;
 
 pub struct Scope<'tcx> {
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 231acbfb488..451cdea35a7 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -16,7 +16,8 @@ use hair::cx::block;
 use hair::cx::to_ref::ToRef;
 use rustc::front::map;
 use rustc::middle::def::Def;
-use rustc::middle::const_eval::{self, ConstVal};
+use rustc::middle::const_val::ConstVal;
+use rustc_const_eval as const_eval;
 use rustc::middle::region::CodeExtent;
 use rustc::middle::pat_util;
 use rustc::ty::{self, VariantDef, Ty};
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index 9bd94e432bf..e4a8363051b 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -18,7 +18,8 @@
 use hair::*;
 use rustc::mir::repr::*;
 
-use rustc::middle::const_eval::{self, ConstVal};
+use rustc::middle::const_val::ConstVal;
+use rustc_const_eval as const_eval;
 use rustc::middle::def_id::DefId;
 use rustc::infer::InferCtxt;
 use rustc::ty::subst::{Subst, Substs};
diff --git a/src/librustc_mir/hair/cx/pattern.rs b/src/librustc_mir/hair/cx/pattern.rs
index 0cb849555f2..c6132a71eef 100644
--- a/src/librustc_mir/hair/cx/pattern.rs
+++ b/src/librustc_mir/hair/cx/pattern.rs
@@ -11,7 +11,7 @@
 use hair::*;
 use hair::cx::Cx;
 use rustc_data_structures::fnv::FnvHashMap;
-use rustc::middle::const_eval;
+use rustc_const_eval as const_eval;
 use rustc::middle::def::Def;
 use rustc::middle::pat_util::{pat_is_resolved_const, pat_is_binding};
 use rustc::ty::{self, Ty};
diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs
index 79c8356bb55..affc1872987 100644
--- a/src/librustc_mir/hair/mod.rs
+++ b/src/librustc_mir/hair/mod.rs
@@ -16,7 +16,7 @@
 
 use rustc::mir::repr::{BinOp, BorrowKind, Field, Literal, Mutability, UnOp,
     TypedConstVal};
-use rustc::middle::const_eval::ConstVal;
+use rustc::middle::const_val::ConstVal;
 use rustc::middle::def_id::DefId;
 use rustc::middle::region::CodeExtent;
 use rustc::ty::subst::Substs;
diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs
index 3b55f62717c..e024fa94fb7 100644
--- a/src/librustc_mir/lib.rs
+++ b/src/librustc_mir/lib.rs
@@ -33,6 +33,7 @@ extern crate rustc_front;
 extern crate rustc_back;
 extern crate syntax;
 extern crate rustc_const_math;
+extern crate rustc_const_eval;
 
 pub mod build;
 pub mod graphviz;
diff --git a/src/librustc_mir/transform/simplify_cfg.rs b/src/librustc_mir/transform/simplify_cfg.rs
index cbde292cb99..00b8f5c0930 100644
--- a/src/librustc_mir/transform/simplify_cfg.rs
+++ b/src/librustc_mir/transform/simplify_cfg.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use rustc::middle::const_eval::ConstVal;
+use rustc::middle::const_val::ConstVal;
 use rustc::ty::TyCtxt;
 use rustc::mir::repr::*;
 use rustc::mir::transform::{MirPass, Pass};
diff --git a/src/librustc_passes/Cargo.toml b/src/librustc_passes/Cargo.toml
index 7cc6510fa1f..02303aa7130 100644
--- a/src/librustc_passes/Cargo.toml
+++ b/src/librustc_passes/Cargo.toml
@@ -11,5 +11,6 @@ crate-type = ["dylib"]
 [dependencies]
 log = { path = "../liblog" }
 rustc = { path = "../librustc" }
+rustc_const_eval = { path = "../librustc_const_eval" }
 rustc_front = { path = "../librustc_front" }
 syntax = { path = "../libsyntax" }
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index 571d5bd9bc5..a33b8caee2e 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -26,9 +26,10 @@
 
 use rustc::dep_graph::DepNode;
 use rustc::ty::cast::{CastKind};
-use rustc::middle::const_eval::{self, ConstEvalErr};
-use rustc::middle::const_eval::ErrKind::IndexOpFeatureGated;
-use rustc::middle::const_eval::EvalHint::ExprTypeChecked;
+use rustc_const_eval::{ConstEvalErr, lookup_const_fn_by_id, compare_lit_exprs};
+use rustc_const_eval::{eval_const_expr_partial, lookup_const_by_id};
+use rustc_const_eval::ErrKind::IndexOpFeatureGated;
+use rustc_const_eval::EvalHint::ExprTypeChecked;
 use rustc::middle::def::Def;
 use rustc::middle::def_id::DefId;
 use rustc::middle::expr_use_visitor as euv;
@@ -169,7 +170,7 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
                             def_id: DefId,
                             ret_ty: Ty<'tcx>)
                             -> bool {
-        if let Some(fn_like) = const_eval::lookup_const_fn_by_id(self.tcx, def_id) {
+        if let Some(fn_like) = lookup_const_fn_by_id(self.tcx, def_id) {
             if
                 // we are in a static/const initializer
                 self.mode != Mode::Var &&
@@ -335,7 +336,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
                 self.global_expr(Mode::Const, &start);
                 self.global_expr(Mode::Const, &end);
 
-                match const_eval::compare_lit_exprs(self.tcx, start, end) {
+                match compare_lit_exprs(self.tcx, start, end) {
                     Some(Ordering::Less) |
                     Some(Ordering::Equal) => {}
                     Some(Ordering::Greater) => {
@@ -431,7 +432,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
                 match node_ty.sty {
                     ty::TyUint(_) | ty::TyInt(_) if div_or_rem => {
                         if !self.qualif.intersects(ConstQualif::NOT_CONST) {
-                            match const_eval::eval_const_expr_partial(
+                            match eval_const_expr_partial(
                                     self.tcx, ex, ExprTypeChecked, None) {
                                 Ok(_) => {}
                                 Err(ConstEvalErr { kind: IndexOpFeatureGated, ..}) => {},
@@ -611,7 +612,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
                 Some(Def::Const(did)) |
                 Some(Def::AssociatedConst(did)) => {
                     let substs = Some(v.tcx.node_id_item_substs(e.id).substs);
-                    if let Some((expr, _)) = const_eval::lookup_const_by_id(v.tcx, did, substs) {
+                    if let Some((expr, _)) = lookup_const_by_id(v.tcx, did, substs) {
                         let inner = v.global_expr(Mode::Const, expr);
                         v.add_qualif(inner);
                     }
diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs
index 91bfb19aa9d..6d217040316 100644
--- a/src/librustc_passes/lib.rs
+++ b/src/librustc_passes/lib.rs
@@ -30,6 +30,7 @@
 extern crate core;
 extern crate rustc;
 extern crate rustc_front;
+extern crate rustc_const_eval;
 
 #[macro_use] extern crate log;
 #[macro_use] extern crate syntax;
diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml
index e884442f03b..b798afe25ed 100644
--- a/src/librustc_trans/Cargo.toml
+++ b/src/librustc_trans/Cargo.toml
@@ -16,6 +16,7 @@ graphviz = { path = "../libgraphviz" }
 log = { path = "../liblog" }
 rustc = { path = "../librustc" }
 rustc_back = { path = "../librustc_back" }
+rustc_const_eval = { path = "../librustc_const_eval" }
 rustc_const_math = { path = "../librustc_const_math" }
 rustc_data_structures = { path = "../librustc_data_structures" }
 rustc_front = { path = "../librustc_front" }
diff --git a/src/librustc_trans/_match.rs b/src/librustc_trans/_match.rs
index 008323ee5bf..f545ba2cbe0 100644
--- a/src/librustc_trans/_match.rs
+++ b/src/librustc_trans/_match.rs
@@ -189,9 +189,8 @@ use self::Opt::*;
 use self::FailureHandler::*;
 
 use llvm::{ValueRef, BasicBlockRef};
-use middle::check_match::StaticInliner;
-use middle::check_match;
-use middle::const_eval;
+use rustc_const_eval::check_match::{self, StaticInliner};
+use rustc_const_eval::{compare_lit_exprs, eval_const_expr};
 use middle::def::{Def, DefMap};
 use middle::def_id::DefId;
 use middle::expr_use_visitor as euv;
@@ -241,7 +240,7 @@ struct ConstantExpr<'a>(&'a hir::Expr);
 
 impl<'a> ConstantExpr<'a> {
     fn eq(self, other: ConstantExpr<'a>, tcx: &TyCtxt) -> bool {
-        match const_eval::compare_lit_exprs(tcx, self.0, other.0) {
+        match compare_lit_exprs(tcx, self.0, other.0) {
             Some(result) => result == Ordering::Equal,
             None => panic!("compare_list_exprs: type mismatch"),
         }
@@ -611,11 +610,11 @@ fn enter_opt<'a, 'p, 'blk, 'tcx>(
 
     let ctor = match opt {
         &ConstantValue(ConstantExpr(expr), _) => check_match::ConstantValue(
-            const_eval::eval_const_expr(bcx.tcx(), &expr)
+            eval_const_expr(bcx.tcx(), &expr)
         ),
         &ConstantRange(ConstantExpr(lo), ConstantExpr(hi), _) => check_match::ConstantRange(
-            const_eval::eval_const_expr(bcx.tcx(), &lo),
-            const_eval::eval_const_expr(bcx.tcx(), &hi)
+            eval_const_expr(bcx.tcx(), &lo),
+            eval_const_expr(bcx.tcx(), &hi)
         ),
         &SliceLengthEqual(n, _) =>
             check_match::Slice(n),
diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs
index b2edcbd9b9e..555c12807ba 100644
--- a/src/librustc_trans/consts.rs
+++ b/src/librustc_trans/consts.rs
@@ -13,7 +13,8 @@ use llvm;
 use llvm::{ConstFCmp, ConstICmp, SetLinkage, SetUnnamedAddr};
 use llvm::{InternalLinkage, ValueRef, Bool, True};
 use middle::const_qualif::ConstQualif;
-use middle::const_eval::{self, ConstEvalErr};
+use rustc_const_eval::{ConstEvalErr, lookup_const_fn_by_id, lookup_const_by_id, ErrKind};
+use rustc_const_eval::eval_repeat_count;
 use middle::def::Def;
 use middle::def_id::DefId;
 use rustc::front::map as hir_map;
@@ -197,7 +198,7 @@ fn const_fn_call<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                            arg_vals: &[ValueRef],
                            param_substs: &'tcx Substs<'tcx>,
                            trueconst: TrueConst) -> Result<ValueRef, ConstEvalFailure> {
-    let fn_like = const_eval::lookup_const_fn_by_id(ccx.tcx(), def_id);
+    let fn_like = lookup_const_fn_by_id(ccx.tcx(), def_id);
     let fn_like = fn_like.expect("lookup_const_fn_by_id failed in const_fn_call");
 
     let body = match fn_like.body().expr {
@@ -228,7 +229,7 @@ pub fn get_const_expr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     let substs = monomorphize::apply_param_substs(ccx.tcx(),
                                                   param_substs,
                                                   &substs.erase_regions());
-    match const_eval::lookup_const_by_id(ccx.tcx(), def_id, Some(substs)) {
+    match lookup_const_by_id(ccx.tcx(), def_id, Some(substs)) {
         Some((ref expr, _ty)) => expr,
         None => {
             ccx.sess().span_bug(ref_expr.span, "constant item not found")
@@ -534,12 +535,12 @@ fn const_err(cx: &CrateContext,
             Ok(())
         },
         (Err(err), TrueConst::Yes) => {
-            let err = ConstEvalErr{ span: e.span, kind: const_eval::ErrKind::Math(err) };
+            let err = ConstEvalErr{ span: e.span, kind: ErrKind::Math(err) };
             cx.tcx().sess.span_err(e.span, &err.description());
             Err(Compiletime(err))
         },
         (Err(err), TrueConst::No) => {
-            let err = ConstEvalErr{ span: e.span, kind: const_eval::ErrKind::Math(err) };
+            let err = ConstEvalErr{ span: e.span, kind: ErrKind::Math(err) };
             cx.tcx().sess.span_warn(e.span, &err.description());
             Err(Runtime(err))
         },
@@ -883,7 +884,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         hir::ExprRepeat(ref elem, ref count) => {
             let unit_ty = ety.sequence_element_type(cx.tcx());
             let llunitty = type_of::type_of(cx, unit_ty);
-            let n = cx.tcx().eval_repeat_count(count);
+            let n = eval_repeat_count(cx.tcx(), count);
             let unit_val = const_expr(cx, &elem, param_substs, fn_args, trueconst)?.0;
             let vs = vec![unit_val; n];
             if val_ty(unit_val) != llunitty {
diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs
index c85008181a4..e9687935538 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -52,6 +52,7 @@ extern crate rustc_mir;
 extern crate rustc_platform_intrinsics as intrinsics;
 extern crate serialize;
 extern crate rustc_const_math;
+extern crate rustc_const_eval;
 
 #[macro_use] extern crate log;
 #[macro_use] extern crate syntax;
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index cdb54eadbdd..2e154c40875 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -10,8 +10,9 @@
 
 use llvm::ValueRef;
 use rustc::ty::{Ty, TypeFoldable};
-use rustc::middle::const_eval::{self, ConstVal};
+use rustc::middle::const_val::ConstVal;
 use rustc_const_math::ConstInt::*;
+use rustc_const_eval::lookup_const_by_id;
 use rustc::mir::repr as mir;
 use abi;
 use common::{self, BlockAndBuilder, C_bool, C_bytes, C_floating_f64, C_integral,
@@ -114,7 +115,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 }
 
                 let substs = Some(bcx.monomorphize(substs));
-                let expr = const_eval::lookup_const_by_id(bcx.tcx(), def_id, substs)
+                let expr = lookup_const_by_id(bcx.tcx(), def_id, substs)
                             .expect("def was const, but lookup_const_by_id failed").0;
                 // FIXME: this is falling back to translating from HIR. This is not easy to fix,
                 // because we would have somehow adapt const_eval to work on MIR rather than HIR.
diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs
index b90be5e0ab6..1396883120b 100644
--- a/src/librustc_trans/mir/rvalue.rs
+++ b/src/librustc_trans/mir/rvalue.rs
@@ -11,7 +11,7 @@
 use llvm::ValueRef;
 use rustc::ty::{self, Ty};
 use rustc::ty::cast::{CastTy, IntTy};
-use middle::const_eval::ConstVal;
+use middle::const_val::ConstVal;
 use rustc_const_math::ConstInt;
 use rustc::mir::repr as mir;
 
diff --git a/src/librustc_trans/tvec.rs b/src/librustc_trans/tvec.rs
index c42bad0bc0b..56ba1b02426 100644
--- a/src/librustc_trans/tvec.rs
+++ b/src/librustc_trans/tvec.rs
@@ -30,6 +30,7 @@ use value::Value;
 use rustc::ty::{self, Ty};
 
 use rustc_front::hir;
+use rustc_const_eval::eval_repeat_count;
 
 use syntax::ast;
 use syntax::parse::token::InternedString;
@@ -218,7 +219,7 @@ fn write_content<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                     return expr::trans_into(bcx, &element, Ignore);
                 }
                 SaveIn(lldest) => {
-                    match bcx.tcx().eval_repeat_count(&count_expr) {
+                    match eval_repeat_count(bcx.tcx(), &count_expr) {
                         0 => expr::trans_into(bcx, &element, Ignore),
                         1 => expr::trans_into(bcx, &element, SaveIn(lldest)),
                         count => {
@@ -270,7 +271,7 @@ fn elements_required(bcx: Block, content_expr: &hir::Expr) -> usize {
         },
         hir::ExprVec(ref es) => es.len(),
         hir::ExprRepeat(_, ref count_expr) => {
-            bcx.tcx().eval_repeat_count(&count_expr)
+            eval_repeat_count(bcx.tcx(), &count_expr)
         }
         _ => bcx.tcx().sess.span_bug(content_expr.span,
                                      "unexpected vec content")
diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml
index 6e1bca87a82..6f46686feb5 100644
--- a/src/librustc_typeck/Cargo.toml
+++ b/src/librustc_typeck/Cargo.toml
@@ -15,6 +15,7 @@ arena = { path = "../libarena" }
 fmt_macros = { path = "../libfmt_macros" }
 rustc = { path = "../librustc" }
 rustc_back = { path = "../librustc_back" }
+rustc_const_eval = { path = "../librustc_const_eval" }
 rustc_const_math = { path = "../librustc_const_math" }
 rustc_front = { path = "../librustc_front" }
 rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" }
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index bd2e0092a89..b7d00716f02 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -49,8 +49,9 @@
 //! an rptr (`&r.T`) use the region `r` that appears in the rptr.
 
 use middle::astconv_util::{prim_ty_to_ty, prohibit_type_params, prohibit_projection};
-use middle::const_eval::{self, ConstVal};
-use middle::const_eval::EvalHint::UncheckedExprHint;
+use middle::const_val::ConstVal;
+use rustc_const_eval::eval_const_expr_partial;
+use rustc_const_eval::EvalHint::UncheckedExprHint;
 use middle::def::{self, Def};
 use middle::def_id::DefId;
 use middle::resolve_lifetime as rl;
@@ -1681,7 +1682,7 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>,
         }
         hir::TyFixedLengthVec(ref ty, ref e) => {
             let hint = UncheckedExprHint(tcx.types.usize);
-            match const_eval::eval_const_expr_partial(tcx, &e, hint, None) {
+            match eval_const_expr_partial(tcx, &e, hint, None) {
                 Ok(ConstVal::Integral(ConstInt::Usize(i))) => {
                     let i = i.as_u64(tcx.sess.target.uint_type);
                     assert_eq!(i as usize as u64, i);
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 107497a2aa3..d90ba03abd4 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -130,6 +130,7 @@ use rustc_front::hir;
 use rustc_front::hir::{Visibility, PatKind};
 use rustc_front::print::pprust;
 use rustc_back::slice;
+use rustc_const_eval::eval_repeat_count;
 
 mod assoc;
 pub mod dropck;
@@ -3592,7 +3593,7 @@ fn check_expr_with_expectation_and_lvalue_pref<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
       }
       hir::ExprRepeat(ref element, ref count_expr) => {
         check_expr_has_type(fcx, &count_expr, tcx.types.usize);
-        let count = fcx.tcx().eval_repeat_count(&count_expr);
+        let count = eval_repeat_count(fcx.tcx(), &count_expr);
 
         let uty = match expected {
             ExpectHasType(uty) => {
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 743a2bb2211..a9ef0fce880 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -66,8 +66,9 @@ use constrained_type_params as ctp;
 use coherence;
 use middle::lang_items::SizedTraitLangItem;
 use middle::resolve_lifetime;
-use middle::const_eval::{self, ConstVal};
-use middle::const_eval::EvalHint::UncheckedExprHint;
+use middle::const_val::ConstVal;
+use rustc_const_eval::EvalHint::UncheckedExprHint;
+use rustc_const_eval::eval_const_expr_partial;
 use rustc::ty::subst::{Substs, FnSpace, ParamSpace, SelfSpace, TypeSpace, VecPerParamSpace};
 use rustc::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer};
 use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeScheme};
@@ -1045,7 +1046,7 @@ fn convert_enum_def<'tcx>(tcx: &TyCtxt<'tcx>,
 
         let ty_hint = repr_ty.to_ty(tcx);
         let hint = UncheckedExprHint(ty_hint);
-        match const_eval::eval_const_expr_partial(tcx, e, hint, None) {
+        match eval_const_expr_partial(tcx, e, hint, None) {
             Ok(ConstVal::Integral(i)) => {
                 // FIXME: eval_const_expr_partial should return an error if the hint is wrong
                 match (repr_ty, i) {
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 9c08f57b833..c3ba9182343 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -93,6 +93,7 @@ extern crate rustc_platform_intrinsics as intrinsics;
 extern crate rustc_front;
 extern crate rustc_back;
 extern crate rustc_const_math;
+extern crate rustc_const_eval;
 
 pub use rustc::dep_graph;
 pub use rustc::front;
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index 6b0ad30f450..3950131129c 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -14,6 +14,7 @@ arena = { path = "../libarena" }
 getopts = { path = "../libgetopts" }
 rustc = { path = "../librustc" }
 rustc_back = { path = "../librustc_back" }
+rustc_const_eval = { path = "../librustc_const_eval" }
 rustc_driver = { path = "../librustc_driver" }
 rustc_front = { path = "../librustc_front" }
 rustc_lint = { path = "../librustc_lint" }
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 702c6dd8211..3e4ba47ce4c 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -22,7 +22,8 @@ use rustc::middle::def_id::DefId;
 use rustc::ty::{self, TyCtxt};
 use rustc::ty::subst;
 use rustc::middle::stability;
-use rustc::middle::const_eval;
+
+use rustc_const_eval::lookup_const_by_id;
 
 use core::DocContext;
 use doctree;
@@ -336,7 +337,7 @@ pub fn build_impl(cx: &DocContext,
                 let did = assoc_const.def_id;
                 let type_scheme = tcx.lookup_item_type(did);
                 let default = if assoc_const.has_value {
-                    Some(const_eval::lookup_const_by_id(tcx, did, None)
+                    Some(lookup_const_by_id(tcx, did, None)
                          .unwrap().0.span.to_src(cx))
                 } else {
                     None
@@ -483,10 +484,9 @@ fn build_module(cx: &DocContext, tcx: &TyCtxt,
 
 fn build_const(cx: &DocContext, tcx: &TyCtxt,
                did: DefId) -> clean::Constant {
-    use rustc::middle::const_eval;
     use rustc_front::print::pprust;
 
-    let (expr, ty) = const_eval::lookup_const_by_id(tcx, did, None).unwrap_or_else(|| {
+    let (expr, ty) = lookup_const_by_id(tcx, did, None).unwrap_or_else(|| {
         panic!("expected lookup_const_by_id to succeed for {:?}", did);
     });
     debug!("converting constant expr {:?} to snippet", expr);
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 90cb78f46a6..a35fe20b6b6 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -35,6 +35,7 @@ extern crate arena;
 extern crate getopts;
 extern crate libc;
 extern crate rustc;
+extern crate rustc_const_eval;
 extern crate rustc_trans;
 extern crate rustc_driver;
 extern crate rustc_resolve;
diff --git a/src/test/auxiliary/dummy_mir_pass.rs b/src/test/auxiliary/dummy_mir_pass.rs
index edf1c2c3a39..fc1ef4d41a8 100644
--- a/src/test/auxiliary/dummy_mir_pass.rs
+++ b/src/test/auxiliary/dummy_mir_pass.rs
@@ -23,7 +23,7 @@ use rustc::mir::transform::{self, MirPass};
 use rustc::mir::repr::{Mir, Literal};
 use rustc::mir::visit::MutVisitor;
 use rustc::ty;
-use rustc::middle::const_eval::ConstVal;
+use rustc::middle::const_val::ConstVal;
 use rustc_const_math::ConstInt;
 use rustc_plugin::Registry;