about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-04-23 08:35:00 +0000
committerbors <bors@rust-lang.org>2017-04-23 08:35:00 +0000
commit23de823e93dc19ef1b9cb65b48860a892cd6ff18 (patch)
tree9b91c1c746a4f520ae69502e0dde070ba23fd9f5 /src
parenta94124488ae0dba1a8a4552a4724cddf9d266e2f (diff)
parent8054377f8f4dfaf766bcff40e7a720c90c5e33be (diff)
downloadrust-23de823e93dc19ef1b9cb65b48860a892cd6ff18.tar.gz
rust-23de823e93dc19ef1b9cb65b48860a892cd6ff18.zip
Auto merge of #41408 - eddyb:poly-const-eval, r=arielb1
rustc: generalize monomorphic_const_eval to polymorphic constants.

With the addition of `Substs` to the query key, we can now evaluate *and cache* polymorphic constants.

Fixes #23898 by replacing the crippled explicit-discriminant-only local-crate-only `lookup_variant_by_id` with `ConstVal::Variant` which can describe variants irrespective of their discriminant.

Fixes #41394 by fixing #23898 (for the original testcase) and by not looping past the first discriminant.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/dep_graph/dep_node.rs4
-rw-r--r--src/librustc/ich/impls_ty.rs9
-rw-r--r--src/librustc/middle/const_val.rs11
-rw-r--r--src/librustc/middle/cstore.rs10
-rw-r--r--src/librustc/mir/mod.rs3
-rw-r--r--src/librustc/ty/maps.rs32
-rw-r--r--src/librustc/ty/mod.rs25
-rw-r--r--src/librustc_const_eval/eval.rs264
-rw-r--r--src/librustc_const_eval/pattern.rs19
-rw-r--r--src/librustc_metadata/cstore_impl.rs15
-rw-r--r--src/librustc_metadata/decoder.rs19
-rw-r--r--src/librustc_mir/hair/cx/expr.rs3
-rw-r--r--src/librustc_trans/mir/constant.rs8
-rw-r--r--src/librustc_typeck/collect.rs3
-rw-r--r--src/librustdoc/clean/inline.rs2
-rw-r--r--src/test/compile-fail/const-call.rs2
-rw-r--r--src/test/compile-fail/const-pattern-not-const-evaluable.rs11
-rw-r--r--src/test/compile-fail/issue-39559.rs4
-rw-r--r--src/test/compile-fail/issue-41394.rs20
-rw-r--r--src/test/run-pass/auxiliary/issue-41394.rs26
-rw-r--r--src/test/run-pass/const-pattern-variant.rs38
-rw-r--r--src/test/run-pass/issue-23898.rs (renamed from src/test/compile-fail/non-constant-enum-for-vec-repeat.rs)5
-rw-r--r--src/test/run-pass/issue-41394.rs17
23 files changed, 331 insertions, 219 deletions
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index 224e9751e73..9a657438522 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -97,7 +97,7 @@ pub enum DepNode<D: Clone + Debug> {
     TypeckBodiesKrate,
     TypeckTables(D),
     UsedTraitImports(D),
-    MonomorphicConstEval(D),
+    ConstEval(D),
 
     // The set of impls for a given trait. Ultimately, it would be
     // nice to get more fine-grained here (e.g., to include a
@@ -233,7 +233,7 @@ impl<D: Clone + Debug> DepNode<D> {
             InherentImpls(ref d) => op(d).map(InherentImpls),
             TypeckTables(ref d) => op(d).map(TypeckTables),
             UsedTraitImports(ref d) => op(d).map(UsedTraitImports),
-            MonomorphicConstEval(ref d) => op(d).map(MonomorphicConstEval),
+            ConstEval(ref d) => op(d).map(ConstEval),
             TraitImpls(ref d) => op(d).map(TraitImpls),
             TraitItems(ref d) => op(d).map(TraitItems),
             ReprHints(ref d) => op(d).map(ReprHints),
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index f55462fb5de..16af98c2035 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -273,6 +273,12 @@ for ::middle::const_val::ConstVal<'tcx> {
             ConstVal::Bool(value) => {
                 value.hash_stable(hcx, hasher);
             }
+            ConstVal::Char(value) => {
+                value.hash_stable(hcx, hasher);
+            }
+            ConstVal::Variant(def_id) => {
+                def_id.hash_stable(hcx, hasher);
+            }
             ConstVal::Function(def_id, substs) => {
                 def_id.hash_stable(hcx, hasher);
                 substs.hash_stable(hcx, hasher);
@@ -296,9 +302,6 @@ for ::middle::const_val::ConstVal<'tcx> {
                 value.hash_stable(hcx, hasher);
                 times.hash_stable(hcx, hasher);
             }
-            ConstVal::Char(value) => {
-                value.hash_stable(hcx, hasher);
-            }
         }
     }
 }
diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs
index b4c5af94019..ec7b3c4dd8d 100644
--- a/src/librustc/middle/const_val.rs
+++ b/src/librustc/middle/const_val.rs
@@ -38,12 +38,13 @@ pub enum ConstVal<'tcx> {
     Str(InternedString),
     ByteStr(Rc<Vec<u8>>),
     Bool(bool),
+    Char(char),
+    Variant(DefId),
     Function(DefId, &'tcx Substs<'tcx>),
     Struct(BTreeMap<ast::Name, ConstVal<'tcx>>),
     Tuple(Vec<ConstVal<'tcx>>),
     Array(Vec<ConstVal<'tcx>>),
     Repeat(Box<ConstVal<'tcx>>, u64),
-    Char(char),
 }
 
 impl<'tcx> ConstVal<'tcx> {
@@ -54,12 +55,13 @@ impl<'tcx> ConstVal<'tcx> {
             Str(_) => "string literal",
             ByteStr(_) => "byte string literal",
             Bool(_) => "boolean",
+            Char(..) => "char",
+            Variant(_) => "enum variant",
             Struct(_) => "struct",
             Tuple(_) => "tuple",
             Function(..) => "function definition",
             Array(..) => "array",
             Repeat(..) => "repeat",
-            Char(..) => "char",
         }
     }
 
@@ -85,7 +87,6 @@ pub enum ErrKind<'tcx> {
     MissingStructField,
     NegateOn(ConstVal<'tcx>),
     NotOn(ConstVal<'tcx>),
-    CallOn(ConstVal<'tcx>),
 
     NonConstPath,
     UnimplementedConstVal(&'static str),
@@ -145,7 +146,6 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
             CannotCast => simple!("can't cast this type"),
             NegateOn(ref const_val) => simple!("negate on {}", const_val.description()),
             NotOn(ref const_val) => simple!("not on {}", const_val.description()),
-            CallOn(ref const_val) => simple!("call on {}", const_val.description()),
 
             MissingStructField  => simple!("nonexistent struct field"),
             NonConstPath        => simple!("non-constant path in constant expression"),
@@ -227,7 +227,8 @@ pub fn eval_length(tcx: TyCtxt,
 {
     let count_expr = &tcx.hir.body(count).value;
     let count_def_id = tcx.hir.body_owner_def_id(count);
-    match ty::queries::monomorphic_const_eval::get(tcx, count_expr.span, count_def_id) {
+    let substs = Substs::empty();
+    match ty::queries::const_eval::get(tcx, count_expr.span, (count_def_id, substs)) {
         Ok(Integral(Usize(count))) => {
             let val = count.as_u64(tcx.sess.target.uint_type);
             assert_eq!(val as usize as u64, val);
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index 20ed2244e86..3251addcb32 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -249,8 +249,8 @@ pub trait CrateStore {
     fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro;
 
     // misc. metadata
-    fn maybe_get_item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                                     -> Option<&'tcx hir::Body>;
+    fn item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
+                           -> &'tcx hir::Body;
     fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap<hir::BodyId, hir::Body>;
     fn const_is_rvalue_promotable_to_static(&self, def: DefId) -> bool;
 
@@ -399,9 +399,9 @@ impl CrateStore for DummyCrateStore {
     fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro { bug!("load_macro") }
 
     // misc. metadata
-    fn maybe_get_item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                                     -> Option<&'tcx hir::Body> {
-        bug!("maybe_get_item_body")
+    fn item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
+                           -> &'tcx hir::Body {
+        bug!("item_body")
     }
     fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap<hir::BodyId, hir::Body> {
         bug!("item_body_nested_bodies")
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 9ff64b295b7..bfb72b5df7b 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -1307,10 +1307,11 @@ fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
             write!(fmt, "b\"{}\"", escaped)
         }
         Bool(b) => write!(fmt, "{:?}", b),
+        Char(c) => write!(fmt, "{:?}", c),
+        Variant(def_id) |
         Function(def_id, _) => write!(fmt, "{}", item_path_str(def_id)),
         Struct(_) | Tuple(_) | Array(_) | Repeat(..) =>
             bug!("ConstVal `{:?}` should not be in MIR", const_val),
-        Char(c) => write!(fmt, "{:?}", c),
     }
 }
 
diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs
index add8db850e4..4247bff0f50 100644
--- a/src/librustc/ty/maps.rs
+++ b/src/librustc/ty/maps.rs
@@ -16,6 +16,7 @@ use middle::privacy::AccessLevels;
 use mir;
 use session::CompileResult;
 use ty::{self, CrateInherentImpls, Ty, TyCtxt};
+use ty::subst::Substs;
 use util::nodemap::NodeSet;
 
 use rustc_data_structures::indexed_vec::IndexVec;
@@ -74,6 +75,15 @@ impl Key for (CrateNum, DefId) {
     }
 }
 
+impl<'tcx> Key for (DefId, &'tcx Substs<'tcx>) {
+    fn map_crate(&self) -> CrateNum {
+        self.0.krate
+    }
+    fn default_span(&self, tcx: TyCtxt) -> Span {
+        self.0.default_span(tcx)
+    }
+}
+
 trait Value<'tcx>: Sized {
     fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self;
 }
@@ -217,6 +227,13 @@ impl<'tcx> QueryDescription for queries::reachable_set<'tcx> {
     }
 }
 
+impl<'tcx> QueryDescription for queries::const_eval<'tcx> {
+    fn describe(tcx: TyCtxt, (def_id, _): (DefId, &'tcx Substs<'tcx>)) -> String {
+        format!("const-evaluating `{}`",
+                tcx.item_path_str(def_id))
+    }
+}
+
 macro_rules! define_maps {
     (<$tcx:tt>
      $($(#[$attr:meta])*
@@ -446,16 +463,17 @@ define_maps! { <'tcx>
     /// (Defined only for LOCAL_CRATE)
     pub crate_inherent_impls_overlap_check: crate_inherent_impls_dep_node(CrateNum) -> (),
 
-    /// Results of evaluating monomorphic constants embedded in
-    /// other items, such as enum variant explicit discriminants.
-    pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> const_val::EvalResult<'tcx>,
+    /// Results of evaluating const items or constants embedded in
+    /// other items (such as enum variant explicit discriminants).
+    pub const_eval: const_eval_dep_node((DefId, &'tcx Substs<'tcx>))
+        -> const_val::EvalResult<'tcx>,
 
     /// Performs the privacy check and computes "access levels".
     pub privacy_access_levels: PrivacyAccessLevels(CrateNum) -> Rc<AccessLevels>,
 
     pub reachable_set: reachability_dep_node(CrateNum) -> Rc<NodeSet>,
 
-    pub mir_shims: mir_shim(ty::InstanceDef<'tcx>) -> &'tcx RefCell<mir::Mir<'tcx>>
+    pub mir_shims: mir_shim_dep_node(ty::InstanceDef<'tcx>) -> &'tcx RefCell<mir::Mir<'tcx>>
 }
 
 fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode<DefId> {
@@ -470,10 +488,14 @@ fn reachability_dep_node(_: CrateNum) -> DepNode<DefId> {
     DepNode::Reachability
 }
 
-fn mir_shim(instance: ty::InstanceDef) -> DepNode<DefId> {
+fn mir_shim_dep_node(instance: ty::InstanceDef) -> DepNode<DefId> {
     instance.dep_node()
 }
 
 fn typeck_item_bodies_dep_node(_: CrateNum) -> DepNode<DefId> {
     DepNode::TypeckBodiesKrate
 }
+
+fn const_eval_dep_node((def_id, _): (DefId, &Substs)) -> DepNode<DefId> {
+    DepNode::ConstEval(def_id)
+}
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 1305b0d9303..cc5eb768d9b 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1693,6 +1693,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
         }
     }
 
+    #[inline]
     pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
                          -> impl Iterator<Item=ConstInt> + 'a {
         let repr_type = self.repr.discr_type();
@@ -1701,11 +1702,18 @@ impl<'a, 'gcx, 'tcx> AdtDef {
         self.variants.iter().map(move |v| {
             let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr());
             if let VariantDiscr::Explicit(expr_did) = v.discr {
-                match queries::monomorphic_const_eval::get(tcx, DUMMY_SP, expr_did) {
+                let substs = Substs::empty();
+                match queries::const_eval::get(tcx, DUMMY_SP, (expr_did, substs)) {
                     Ok(ConstVal::Integral(v)) => {
                         discr = v;
                     }
-                    _ => {}
+                    err => {
+                        if !expr_did.is_local() {
+                            span_bug!(tcx.def_span(expr_did),
+                                "variant discriminant evaluation succeeded \
+                                 in its crate but failed locally: {:?}", err);
+                        }
+                    }
                 }
             }
             prev_discr = Some(discr);
@@ -1733,12 +1741,21 @@ impl<'a, 'gcx, 'tcx> AdtDef {
                     explicit_index -= distance;
                 }
                 ty::VariantDiscr::Explicit(expr_did) => {
-                    match queries::monomorphic_const_eval::get(tcx, DUMMY_SP, expr_did) {
+                    let substs = Substs::empty();
+                    match queries::const_eval::get(tcx, DUMMY_SP, (expr_did, substs)) {
                         Ok(ConstVal::Integral(v)) => {
                             explicit_value = v;
                             break;
                         }
-                        _ => {
+                        err => {
+                            if !expr_did.is_local() {
+                                span_bug!(tcx.def_span(expr_did),
+                                    "variant discriminant evaluation succeeded \
+                                     in its crate but failed locally: {:?}", err);
+                            }
+                            if explicit_index == 0 {
+                                break;
+                            }
                             explicit_index -= 1;
                         }
                     }
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index 9c5a669bef0..e9352f53c92 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -15,7 +15,7 @@ use rustc::middle::const_val::{ConstVal, ConstEvalErr, EvalResult, ErrKind};
 use rustc::hir::map as hir_map;
 use rustc::hir::map::blocks::FnLikeNode;
 use rustc::traits;
-use rustc::hir::def::Def;
+use rustc::hir::def::{Def, CtorKind};
 use rustc::hir::def_id::DefId;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::maps::Providers;
@@ -48,110 +48,39 @@ macro_rules! math {
     }
 }
 
-fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                  variant_def: DefId)
-                                  -> Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)> {
-    if let Some(variant_node_id) = tcx.hir.as_local_node_id(variant_def) {
-        let enum_node_id = tcx.hir.get_parent(variant_node_id);
-        if let Some(hir_map::NodeItem(it)) = tcx.hir.find(enum_node_id) {
-            if let hir::ItemEnum(ref edef, _) = it.node {
-                for variant in &edef.variants {
-                    if variant.node.data.id() == variant_node_id {
-                        return variant.node.disr_expr.map(|e| {
-                            let def_id = tcx.hir.body_owner_def_id(e);
-                            (&tcx.hir.body(e).value,
-                             tcx.item_tables(def_id))
-                        });
-                    }
-                }
-            }
-        }
-    }
-    None
-}
-
 /// * `def_id` is the id of the constant.
 /// * `substs` is the monomorphized substitutions for the expression.
 ///
 /// `substs` is optional and is used for associated constants.
 /// This generally happens in late/trans const evaluation.
-pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                        def_id: DefId,
-                                        substs: &'tcx Substs<'tcx>)
-                                        -> Option<(&'tcx Expr,
-                                                   &'a ty::TypeckTables<'tcx>)> {
+pub fn lookup_const_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                    def_id: DefId,
+                                    substs: &'tcx Substs<'tcx>)
+                                    -> Option<(DefId, &'tcx Substs<'tcx>)> {
     if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
         match tcx.hir.find(node_id) {
-            None => None,
-            Some(hir_map::NodeItem(&hir::Item {
-                node: hir::ItemConst(_, body), ..
-            })) |
-            Some(hir_map::NodeImplItem(&hir::ImplItem {
-                node: hir::ImplItemKind::Const(_, body), ..
-            })) => {
-                Some((&tcx.hir.body(body).value,
-                      tcx.item_tables(def_id)))
+            Some(hir_map::NodeTraitItem(_)) => {
+                // If we have a trait item and the substitutions for it,
+                // `resolve_trait_associated_const` will select an impl
+                // or the default.
+                resolve_trait_associated_const(tcx, def_id, substs)
             }
-            Some(hir_map::NodeTraitItem(ti)) => match ti.node {
-                hir::TraitItemKind::Const(_, default) => {
-                    // If we have a trait item and the substitutions for it,
-                    // `resolve_trait_associated_const` will select an impl
-                    // or the default.
-                    let trait_id = tcx.hir.get_parent(node_id);
-                    let trait_id = tcx.hir.local_def_id(trait_id);
-                    let default_value = default.map(|body| {
-                        (&tcx.hir.body(body).value,
-                            tcx.item_tables(def_id))
-                    });
-                    resolve_trait_associated_const(tcx, def_id, default_value, trait_id, substs)
-                }
-                _ => None
-            },
-            Some(_) => None
+            _ => Some((def_id, substs))
         }
     } else {
-        let expr_and_tables = tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
-            (&body.value, tcx.item_tables(def_id))
-        });
         match tcx.sess.cstore.describe_def(def_id) {
             Some(Def::AssociatedConst(_)) => {
-                let trait_id = tcx.sess.cstore.trait_of_item(def_id);
                 // As mentioned in the comments above for in-crate
                 // constants, we only try to find the expression for a
                 // trait-associated const if the caller gives us the
                 // substitutions for the reference to it.
-                if let Some(trait_id) = trait_id {
-                    resolve_trait_associated_const(tcx, def_id, expr_and_tables,
-                                                   trait_id, substs)
+                if tcx.sess.cstore.trait_of_item(def_id).is_some() {
+                    resolve_trait_associated_const(tcx, def_id, substs)
                 } else {
-                    expr_and_tables
+                    Some((def_id, substs))
                 }
-            },
-            Some(Def::Const(..)) => expr_and_tables,
-            _ => None
-        }
-    }
-}
-
-fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
-                                   -> Option<(&'tcx hir::Body, &'a ty::TypeckTables<'tcx>)>
-{
-    if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
-        FnLikeNode::from_node(tcx.hir.get(node_id)).and_then(|fn_like| {
-            if fn_like.constness() == hir::Constness::Const {
-                Some((tcx.hir.body(fn_like.body()),
-                      tcx.item_tables(def_id)))
-            } else {
-                None
             }
-        })
-    } else {
-        if tcx.sess.cstore.is_const_fn(def_id) {
-            tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
-                (body, tcx.item_tables(def_id))
-            })
-        } else {
-            None
+            _ => Some((def_id, substs))
         }
     }
 }
@@ -338,9 +267,22 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
         }
       }
       hir::ExprCast(ref base, _) => {
-        match cast_const(tcx, cx.eval(base)?, ety) {
-            Ok(val) => val,
-            Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }),
+        let base_val = cx.eval(base)?;
+        let base_ty = cx.tables.expr_ty(base);
+
+        // Avoid applying substitutions if they're empty, that'd ICE.
+        let base_ty = if cx.substs.is_empty() {
+            base_ty
+        } else {
+            base_ty.subst(tcx, cx.substs)
+        };
+        if ety == base_ty {
+            base_val
+        } else {
+            match cast_const(tcx, base_val, ety) {
+                Ok(val) => val,
+                Err(kind) => signal!(e, kind),
+            }
         }
       }
       hir::ExprPath(ref qpath) => {
@@ -357,42 +299,29 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
           match cx.tables.qpath_def(qpath, e.id) {
               Def::Const(def_id) |
               Def::AssociatedConst(def_id) => {
-                  if let Some((expr, tables)) = lookup_const_by_id(tcx, def_id, substs) {
-                      let cx = ConstContext::with_tables(tcx, tables);
-                      match cx.eval(expr) {
-                          Ok(val) => val,
-                          Err(ConstEvalErr { kind: TypeckError, .. }) => {
-                              signal!(e, TypeckError);
-                          }
-                          Err(err) => {
-                              debug!("bad reference: {:?}, {:?}", err.description(), err.span);
-                              signal!(e, ErroneousReferencedConstant(box err))
-                          },
-                      }
-                  } else {
-                      signal!(e, TypeckError);
-                  }
+                    match ty::queries::const_eval::get(tcx, e.span, (def_id, substs)) {
+                        Ok(val) => val,
+                        Err(ConstEvalErr { kind: TypeckError, .. }) => {
+                            signal!(e, TypeckError);
+                        }
+                        Err(err) => {
+                            debug!("bad reference: {:?}, {:?}", err.description(), err.span);
+                            signal!(e, ErroneousReferencedConstant(box err))
+                        },
+                    }
               },
-              Def::VariantCtor(variant_def, ..) => {
-                  if let Some((expr, tables)) = lookup_variant_by_id(tcx, variant_def) {
-                      let cx = ConstContext::with_tables(tcx, tables);
-                      match cx.eval(expr) {
-                          Ok(val) => val,
-                          Err(ConstEvalErr { kind: TypeckError, .. }) => {
-                              signal!(e, TypeckError);
-                          }
-                          Err(err) => {
-                              debug!("bad reference: {:?}, {:?}", err.description(), err.span);
-                              signal!(e, ErroneousReferencedConstant(box err))
-                          },
-                      }
-                  } else {
-                      signal!(e, UnimplementedConstVal("enum variants"));
-                  }
+              Def::VariantCtor(variant_def, CtorKind::Const) => {
+                Variant(variant_def)
+              }
+              Def::VariantCtor(_, CtorKind::Fn) => {
+                  signal!(e, UnimplementedConstVal("enum variants"));
               }
-              Def::StructCtor(..) => {
+              Def::StructCtor(_, CtorKind::Const) => {
                   ConstVal::Struct(Default::default())
               }
+              Def::StructCtor(_, CtorKind::Fn) => {
+                  signal!(e, UnimplementedConstVal("tuple struct constructors"))
+              }
               Def::Local(def_id) => {
                   debug!("Def::Local({:?}): {:?}", def_id, cx.fn_args);
                   if let Some(val) = cx.fn_args.as_ref().and_then(|args| args.get(&def_id)) {
@@ -407,14 +336,27 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
           }
       }
       hir::ExprCall(ref callee, ref args) => {
-          let (did, substs) = match cx.eval(callee)? {
-              Function(did, substs) => (did, substs),
-              Struct(_) => signal!(e, UnimplementedConstVal("tuple struct constructors")),
-              callee => signal!(e, CallOn(callee)),
+          let (def_id, substs) = match cx.eval(callee)? {
+              Function(def_id, substs) => (def_id, substs),
+              _ => signal!(e, TypeckError),
           };
-          let (body, tables) = match lookup_const_fn_by_id(tcx, did) {
-              Some(x) => x,
-              None => signal!(e, NonConstPath),
+
+          let body = if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
+            if let Some(fn_like) = FnLikeNode::from_node(tcx.hir.get(node_id)) {
+                if fn_like.constness() == hir::Constness::Const {
+                    tcx.hir.body(fn_like.body())
+                } else {
+                    signal!(e, TypeckError)
+                }
+            } else {
+                signal!(e, TypeckError)
+            }
+          } else {
+            if tcx.sess.cstore.is_const_fn(def_id) {
+                tcx.sess.cstore.item_body(tcx, def_id)
+            } else {
+                signal!(e, TypeckError)
+            }
           };
 
           let arg_defs = body.arguments.iter().map(|arg| match arg.pat.node {
@@ -434,7 +376,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
           debug!("const call({:?})", call_args);
           let callee_cx = ConstContext {
             tcx: tcx,
-            tables: tables,
+            tables: tcx.item_tables(def_id),
             substs: substs,
             fn_args: Some(call_args)
           };
@@ -532,19 +474,16 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
     Ok(result)
 }
 
-fn resolve_trait_associated_const<'a, 'tcx: 'a>(
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    trait_item_id: DefId,
-    default_value: Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)>,
-    trait_id: DefId,
-    rcvr_substs: &'tcx Substs<'tcx>
-) -> Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)>
-{
-    let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, rcvr_substs));
+fn resolve_trait_associated_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                            def_id: DefId,
+                                            substs: &'tcx Substs<'tcx>)
+                                            -> Option<(DefId, &'tcx Substs<'tcx>)> {
+    let trait_item = tcx.associated_item(def_id);
+    let trait_id = trait_item.container.id();
+    let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, substs));
     debug!("resolve_trait_associated_const: trait_ref={:?}",
            trait_ref);
 
-    tcx.populate_implementations_for_trait_if_necessary(trait_id);
     tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
         let mut selcx = traits::SelectionContext::new(&infcx);
         let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
@@ -569,12 +508,20 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(
         // when constructing the inference context above.
         match selection {
             traits::VtableImpl(ref impl_data) => {
-                let name = tcx.associated_item(trait_item_id).name;
+                let name = trait_item.name;
                 let ac = tcx.associated_items(impl_data.impl_def_id)
                     .find(|item| item.kind == ty::AssociatedKind::Const && item.name == name);
                 match ac {
-                    Some(ic) => lookup_const_by_id(tcx, ic.def_id, Substs::empty()),
-                    None => default_value,
+                    // FIXME(eddyb) Use proper Instance resolution to
+                    // get the correct Substs returned from here.
+                    Some(ic) => Some((ic.def_id, Substs::empty())),
+                    None => {
+                        if trait_item.defaultness.has_value() {
+                            Some((def_id, substs))
+                        } else {
+                            None
+                        }
+                    }
                 }
             }
             _ => {
@@ -615,7 +562,7 @@ fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             U8(u) => Ok(Char(u as char)),
             _ => bug!(),
         },
-        _ => bug!(),
+        _ => Err(CannotCast),
     }
 }
 
@@ -659,6 +606,11 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         Bool(b) => cast_const_int(tcx, U8(b as u8), ty),
         Float(f) => cast_const_float(tcx, f, ty),
         Char(c) => cast_const_int(tcx, U32(c as u32), ty),
+        Variant(v) => {
+            let adt = tcx.lookup_adt_def(tcx.parent_def_id(v).unwrap());
+            let idx = adt.variant_index_with_id(v);
+            cast_const_int(tcx, adt.discriminant_for_variant(tcx, idx), ty)
+        }
         Function(..) => Err(UnimplementedConstVal("casting fn pointers")),
         ByteStr(b) => match ty.sty {
             ty::TyRawPtr(_) => {
@@ -796,21 +748,35 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> {
 
 pub fn provide(providers: &mut Providers) {
     *providers = Providers {
-        monomorphic_const_eval,
+        const_eval,
         ..*providers
     };
 }
 
-fn monomorphic_const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                    def_id: DefId)
-                                    -> EvalResult<'tcx> {
-    let cx = ConstContext::with_tables(tcx, tcx.item_tables(def_id));
+fn const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                        (def_id, substs): (DefId, &'tcx Substs<'tcx>))
+                        -> EvalResult<'tcx> {
+    let (def_id, substs) = if let Some(resolved) = lookup_const_by_id(tcx, def_id, substs) {
+        resolved
+    } else {
+        return Err(ConstEvalErr {
+            span: tcx.def_span(def_id),
+            kind: TypeckError
+        });
+    };
+
+    let cx = ConstContext {
+        tcx,
+        tables: tcx.item_tables(def_id),
+        substs: substs,
+        fn_args: None
+    };
 
     let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) {
         ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id);
         tcx.hir.body(tcx.hir.body_owned_by(id))
     } else {
-        tcx.sess.cstore.maybe_get_item_body(tcx, def_id).unwrap()
+        tcx.sess.cstore.item_body(tcx, def_id)
     };
     cx.eval(&body.value)
 }
diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs
index f20fa27dc22..0dfafeb6fb8 100644
--- a/src/librustc_const_eval/pattern.rs
+++ b/src/librustc_const_eval/pattern.rs
@@ -116,6 +116,7 @@ fn print_const_val(value: &ConstVal, f: &mut fmt::Formatter) -> fmt::Result {
         ConstVal::ByteStr(ref b) => write!(f, "{:?}", &b[..]),
         ConstVal::Bool(b) => write!(f, "{:?}", b),
         ConstVal::Char(c) => write!(f, "{:?}", c),
+        ConstVal::Variant(_) |
         ConstVal::Struct(_) |
         ConstVal::Tuple(_) |
         ConstVal::Function(..) |
@@ -587,11 +588,16 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
                 let substs = self.tables.node_id_item_substs(id)
                     .unwrap_or_else(|| tcx.intern_substs(&[]));
                 match eval::lookup_const_by_id(tcx, def_id, substs) {
-                    Some((const_expr, const_tables)) => {
+                    Some((def_id, _substs)) => {
                         // Enter the inlined constant's tables temporarily.
                         let old_tables = self.tables;
-                        self.tables = const_tables;
-                        let pat = self.lower_const_expr(const_expr, pat_id, span);
+                        self.tables = tcx.item_tables(def_id);
+                        let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) {
+                            tcx.hir.body(tcx.hir.body_owned_by(id))
+                        } else {
+                            tcx.sess.cstore.item_body(tcx, def_id)
+                        };
+                        let pat = self.lower_const_expr(&body.value, pat_id, span);
                         self.tables = old_tables;
                         return pat;
                     }
@@ -615,7 +621,12 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
         let const_cx = eval::ConstContext::with_tables(self.tcx.global_tcx(), self.tables);
         match const_cx.eval(expr) {
             Ok(value) => {
-                PatternKind::Constant { value: value }
+                if let ConstVal::Variant(def_id) = value {
+                    let ty = self.tables.expr_ty(expr);
+                    self.lower_variant_or_leaf(Def::Variant(def_id), ty, vec![])
+                } else {
+                    PatternKind::Constant { value: value }
+                }
             }
             Err(e) => {
                 self.errors.push(PatternError::ConstEval(e));
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index cb1b0c4c0b7..9e6a45e7f8b 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -420,19 +420,18 @@ impl CrateStore for cstore::CStore {
         })
     }
 
-    fn maybe_get_item_body<'a, 'tcx>(&self,
-                                     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                     def_id: DefId)
-                                     -> Option<&'tcx hir::Body>
-    {
+    fn item_body<'a, 'tcx>(&self,
+                           tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                           def_id: DefId)
+                           -> &'tcx hir::Body {
         if let Some(cached) = tcx.hir.get_inlined_body(def_id) {
-            return Some(cached);
+            return cached;
         }
 
         self.dep_graph.read(DepNode::MetaData(def_id));
-        debug!("maybe_get_item_body({}): inlining item", tcx.item_path_str(def_id));
+        debug!("item_body({}): inlining item", tcx.item_path_str(def_id));
 
-        self.get_crate_data(def_id.krate).maybe_get_item_body(tcx, def_id.index)
+        self.get_crate_data(def_id.krate).item_body(tcx, def_id.index)
     }
 
     fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap<hir::BodyId, hir::Body> {
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 2d562aceb65..a9eae5281b2 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -750,16 +750,15 @@ impl<'a, 'tcx> CrateMetadata {
         }
     }
 
-    pub fn maybe_get_item_body(&self,
-                               tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                               id: DefIndex)
-                               -> Option<&'tcx hir::Body> {
-        if self.is_proc_macro(id) { return None; }
-        self.entry(id).ast.map(|ast| {
-            let def_id = self.local_def_id(id);
-            let body = ast.decode(self).body.decode(self);
-            tcx.hir.intern_inlined_body(def_id, body)
-        })
+    pub fn item_body(&self,
+                     tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                     id: DefIndex)
+                     -> &'tcx hir::Body {
+        assert!(!self.is_proc_macro(id));
+        let ast = self.entry(id).ast.unwrap();
+        let def_id = self.local_def_id(id);
+        let body = ast.decode(self).body.decode(self);
+        tcx.hir.intern_inlined_body(def_id, body)
     }
 
     pub fn item_body_tables(&self,
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index b7de50efe34..736c076ea15 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -593,7 +593,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         hir::ExprRepeat(ref v, count) => {
             let c = &cx.tcx.hir.body(count).value;
             let def_id = cx.tcx.hir.body_owner_def_id(count);
-            let count = match ty::queries::monomorphic_const_eval::get(cx.tcx, c.span, def_id) {
+            let substs = Substs::empty();
+            let count = match ty::queries::const_eval::get(cx.tcx, c.span, (def_id, substs)) {
                 Ok(ConstVal::Integral(ConstInt::Usize(u))) => u,
                 Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other),
                 Err(s) => cx.fatal_const_eval_err(&s, c.span, "expression")
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index e938913a3f1..040194e63d0 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -100,15 +100,13 @@ impl<'tcx> Const<'tcx> {
             ConstVal::Integral(ref i) => return Const::from_constint(ccx, i),
             ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()),
             ConstVal::ByteStr(ref v) => consts::addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"),
+            ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false),
+            ConstVal::Function(..) => C_null(type_of::type_of(ccx, ty)),
+            ConstVal::Variant(_) |
             ConstVal::Struct(_) | ConstVal::Tuple(_) |
             ConstVal::Array(..) | ConstVal::Repeat(..) => {
                 bug!("MIR must not use `{:?}` (aggregates are expanded to MIR rvalues)", cv)
             }
-            ConstVal::Function(..) => {
-                let llty = type_of::type_of(ccx, ty);
-                return Const::new(C_null(llty), ty);
-            }
-            ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false),
         };
 
         assert!(!ty.has_erasable_regions());
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 1f2310c49e3..660ce837043 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -555,7 +555,8 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         let wrapped_discr = prev_discr.map_or(initial, |d| d.wrap_incr());
         prev_discr = Some(if let Some(e) = variant.node.disr_expr {
             let expr_did = tcx.hir.local_def_id(e.node_id);
-            let result = ty::queries::monomorphic_const_eval::get(tcx, variant.span, expr_did);
+            let substs = Substs::empty();
+            let result = ty::queries::const_eval::get(tcx, variant.span, (expr_did, substs));
 
             // enum variant evaluation happens before the global constant check
             // so we need to report the real error
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index cc30fdf56fc..6016fd488f5 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -487,7 +487,7 @@ impl hir::print::PpAnn for InlinedConst {
 }
 
 fn print_inlined_const(cx: &DocContext, did: DefId) -> String {
-    let body = cx.tcx.sess.cstore.maybe_get_item_body(cx.tcx, did).unwrap();
+    let body = cx.tcx.sess.cstore.item_body(cx.tcx, did);
     let inlined = InlinedConst {
         nested_bodies: cx.tcx.sess.cstore.item_body_nested_bodies(did)
     };
diff --git a/src/test/compile-fail/const-call.rs b/src/test/compile-fail/const-call.rs
index ff83dd004a2..0745ac02d07 100644
--- a/src/test/compile-fail/const-call.rs
+++ b/src/test/compile-fail/const-call.rs
@@ -17,6 +17,4 @@ fn f(x: usize) -> usize {
 fn main() {
     let _ = [0; f(2)];
     //~^ ERROR calls in constants are limited to constant functions
-    //~| ERROR constant evaluation error [E0080]
-    //~| non-constant path in constant expression
 }
diff --git a/src/test/compile-fail/const-pattern-not-const-evaluable.rs b/src/test/compile-fail/const-pattern-not-const-evaluable.rs
index b40aa2a8e27..71cac3edbc1 100644
--- a/src/test/compile-fail/const-pattern-not-const-evaluable.rs
+++ b/src/test/compile-fail/const-pattern-not-const-evaluable.rs
@@ -10,21 +10,22 @@
 
 #![feature(const_fn)]
 
+#[derive(PartialEq, Eq)]
 enum Cake {
     BlackForest,
     Marmor,
 }
 use Cake::*;
 
-const BOO: (Cake, Cake) = (Marmor, BlackForest);
+struct Pair<A, B>(A, B);
+
+const BOO: Pair<Cake, Cake> = Pair(Marmor, BlackForest);
 //~^ ERROR: constant evaluation error [E0080]
-//~| unimplemented constant expression: enum variants
+//~| unimplemented constant expression: tuple struct constructors
 const FOO: Cake = BOO.1;
 
 const fn foo() -> Cake {
     Marmor
-        //~^ ERROR: constant evaluation error [E0080]
-        //~| unimplemented constant expression: enum variants
 }
 
 const WORKS: Cake = Marmor;
@@ -34,7 +35,7 @@ const GOO: Cake = foo();
 fn main() {
     match BlackForest {
         FOO => println!("hi"), //~ NOTE: for pattern here
-        GOO => println!("meh"), //~ NOTE: for pattern here
+        GOO => println!("meh"),
         WORKS => println!("möp"),
         _ => println!("bye"),
     }
diff --git a/src/test/compile-fail/issue-39559.rs b/src/test/compile-fail/issue-39559.rs
index 06e8406cbc0..b7f767f109c 100644
--- a/src/test/compile-fail/issue-39559.rs
+++ b/src/test/compile-fail/issue-39559.rs
@@ -28,10 +28,6 @@ pub struct Vector<T, D: Dim> {
 fn main() {
     let array: [usize; Dim3::dim()]
     //~^ ERROR calls in constants are limited to constant functions
-    //~| ERROR constant evaluation error
-    //~| non-constant path in constant expression
         = [0; Dim3::dim()];
         //~^ ERROR calls in constants are limited to constant functions
-        //~| ERROR constant evaluation error
-        //~| non-constant path in constant expression
 }
diff --git a/src/test/compile-fail/issue-41394.rs b/src/test/compile-fail/issue-41394.rs
new file mode 100644
index 00000000000..1fb3b7c4ee1
--- /dev/null
+++ b/src/test/compile-fail/issue-41394.rs
@@ -0,0 +1,20 @@
+// Copyright 2017 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.
+
+enum Foo {
+    A = "" + 1
+    //~^ ERROR binary operation `+` cannot be applied to type `&'static str`
+}
+
+enum Bar {
+    A = Foo::A as isize
+}
+
+fn main() {}
diff --git a/src/test/run-pass/auxiliary/issue-41394.rs b/src/test/run-pass/auxiliary/issue-41394.rs
new file mode 100644
index 00000000000..f06b81279ac
--- /dev/null
+++ b/src/test/run-pass/auxiliary/issue-41394.rs
@@ -0,0 +1,26 @@
+// Copyright 2017 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.
+
+#![crate_type = "lib"]
+
+#[repr(u32)]
+pub enum Foo {
+    Foo = Private::Variant as u32
+}
+
+#[repr(u8)]
+enum Private {
+    Variant = 42
+}
+
+#[inline(always)]
+pub fn foo() -> Foo {
+    Foo::Foo
+}
diff --git a/src/test/run-pass/const-pattern-variant.rs b/src/test/run-pass/const-pattern-variant.rs
new file mode 100644
index 00000000000..104ab6e19db
--- /dev/null
+++ b/src/test/run-pass/const-pattern-variant.rs
@@ -0,0 +1,38 @@
+// Copyright 2015 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.
+
+#![feature(const_fn)]
+
+#[derive(PartialEq, Eq)]
+enum Cake {
+    BlackForest,
+    Marmor,
+}
+use Cake::*;
+
+const BOO: (Cake, Cake) = (Marmor, BlackForest);
+const FOO: Cake = BOO.1;
+
+const fn foo() -> Cake {
+    Marmor
+}
+
+const WORKS: Cake = Marmor;
+
+const GOO: Cake = foo();
+
+fn main() {
+    match BlackForest {
+        FOO => println!("hi"),
+        GOO => println!("meh"),
+        WORKS => println!("möp"),
+        _ => println!("bye"),
+    }
+}
diff --git a/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs b/src/test/run-pass/issue-23898.rs
index cadfec5a38d..3f5546ce83d 100644
--- a/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs
+++ b/src/test/run-pass/issue-23898.rs
@@ -8,13 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// Note: This test is checking that we forbid a coding pattern that
-// Issue #5873 explicitly wants to allow.
+// Note: This test was used to demonstrate #5873 (now #23898).
 
 enum State { ST_NULL, ST_WHITESPACE }
 
 fn main() {
     [State::ST_NULL; (State::ST_WHITESPACE as usize)];
-    //~^ ERROR constant evaluation error
-    //~| unimplemented constant expression: enum variants
 }
diff --git a/src/test/run-pass/issue-41394.rs b/src/test/run-pass/issue-41394.rs
new file mode 100644
index 00000000000..798905599a8
--- /dev/null
+++ b/src/test/run-pass/issue-41394.rs
@@ -0,0 +1,17 @@
+// Copyright 2017 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.
+
+// aux-build:issue-41394.rs
+
+extern crate issue_41394 as lib;
+
+fn main() {
+    assert_eq!(lib::foo() as u32, 42);
+}