diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs
index 3621cb267d91f..2e7e9335ed118 100644
--- a/src/librustc/middle/const_val.rs
+++ b/src/librustc/middle/const_val.rs
@@ -17,6 +17,8 @@ use std::mem::transmute;
 use rustc_const_math::*;
 use self::ConstVal::*;
 
+use std::collections::BTreeMap;
+
 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
 pub enum ConstVal {
     Float(f64),
@@ -24,11 +26,13 @@ pub enum ConstVal {
     Str(InternedString),
     ByteStr(Rc<Vec<u8>>),
     Bool(bool),
-    Struct(ast::NodeId),
-    Tuple(ast::NodeId),
+    Struct(DefId, BTreeMap<ast::Name, ConstVal>),
+    /// Tuple or Tuple structs
+    Tuple(Option<DefId>, Vec<ConstVal>),
+    /// A function pointer
     Function(DefId),
-    Array(ast::NodeId, u64),
-    Repeat(ast::NodeId, u64),
+    Array(Vec<ConstVal>),
+    Repeat(Box<ConstVal>, 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
@@ -44,11 +48,26 @@ impl hash::Hash for ConstVal {
             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),
+            Struct(did, ref tree) => {
+                did.hash(state);
+                for (name, val) in tree {
+                    name.hash(state);
+                    val.hash(state);
+                }
+            },
+            Tuple(did, ref v) => {
+                did.hash(state);
+                for elem in v {
+                    elem.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) },
+            Array(ref v) => {
+                for elem in v {
+                    elem.hash(state);
+                }
+            }
+            Repeat(ref a, n) => { a.hash(state); n.hash(state) },
             Char(c) => c.hash(state),
             Dummy => ().hash(state),
         }
@@ -67,11 +86,11 @@ impl PartialEq for ConstVal {
             (&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,
+            (&Struct(a_did, ref a), &Struct(b_did, ref b)) => (a == b) && (a_did == b_did),
+            (&Tuple(ref a_did, ref a), &Tuple(ref b_did, ref b)) => (a == b) && (a_did == b_did),
             (&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),
+            (&Array(ref a), &Array(ref b)) => a == b,
+            (&Repeat(ref a, an), &Repeat(ref b, bn)) => (a == b) && (an == bn),
             (&Char(a), &Char(b)) => a == b,
             (&Dummy, &Dummy) => true, // FIXME: should this be false?
             _ => false,
@@ -89,8 +108,8 @@ impl ConstVal {
             Str(_) => "string literal",
             ByteStr(_) => "byte string literal",
             Bool(_) => "boolean",
-            Struct(_) => "struct",
-            Tuple(_) => "tuple",
+            Struct(..) => "struct",
+            Tuple(..) => "tuple",
             Function(_) => "function definition",
             Array(..) => "array",
             Repeat(..) => "repeat",
diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs
index 458cb28144adb..ab2f21fe822b9 100644
--- a/src/librustc/mir/repr.rs
+++ b/src/librustc/mir/repr.rs
@@ -22,7 +22,7 @@ use std::borrow::{Cow};
 use std::fmt::{self, Debug, Formatter, Write};
 use std::{iter, u32};
 use std::ops::{Index, IndexMut};
-use syntax::ast::{self, Name};
+use syntax::ast::Name;
 use syntax::codemap::Span;
 
 /// Lowered representation of a single function.
@@ -1039,17 +1039,48 @@ fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
         }
         Bool(b) => write!(fmt, "{:?}", b),
         Function(def_id) => write!(fmt, "{}", item_path_str(def_id)),
-        Struct(node_id) | Tuple(node_id) | Array(node_id, _) | Repeat(node_id, _) =>
-            write!(fmt, "{}", node_to_string(node_id)),
+        Struct(def_id, ref tree) => {
+            write!(fmt, "{}", item_path_str(def_id))?;
+            if !tree.is_empty() {
+                write!(fmt, "{{")?;
+                for (name, val) in tree {
+                    write!(fmt, "{}:", name)?;
+                    fmt_const_val(fmt, val)?;
+                    write!(fmt, ",")?;
+                }
+                write!(fmt, "}}")?;
+            }
+            Ok(())
+        },
+        Tuple(def_id, ref v) => {
+            if let Some(def_id) = def_id {
+                write!(fmt, "{}", item_path_str(def_id))?;
+            }
+            write!(fmt, "(")?;
+            for val in v {
+                fmt_const_val(fmt, val)?;
+                write!(fmt, ",")?;
+            }
+            write!(fmt, ")")
+        },
+        Array(ref v) => {
+            write!(fmt, "[")?;
+            for val in v {
+                fmt_const_val(fmt, val)?;
+                write!(fmt, ",")?;
+            }
+            write!(fmt, "]")
+        },
+        Repeat(ref v, n) => {
+            write!(fmt, "[")?;
+            fmt_const_val(fmt, v)?;
+            write!(fmt, ";{}]", n)
+        },
         Char(c) => write!(fmt, "{:?}", c),
         Dummy => bug!(),
     }
 }
 
-fn node_to_string(node_id: ast::NodeId) -> String {
-    ty::tls::with(|tcx| tcx.map.node_to_user_string(node_id))
-}
-
 fn item_path_str(def_id: DefId) -> String {
     ty::tls::with(|tcx| tcx.item_path_str(def_id))
 }
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index 9db24fa4770fe..d2cd50b3d606c 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -41,6 +41,7 @@ use syntax::attr::IntType;
 use std::borrow::Cow;
 use std::cmp::Ordering;
 use std::collections::hash_map::Entry::Vacant;
+use std::collections::BTreeMap;
 
 use rustc_const_math::*;
 
@@ -410,9 +411,11 @@ pub enum ErrKind {
     IntermediateUnsignedNegative,
     /// Expected, Got
     TypeMismatch(String, ConstInt),
-    BadType(ConstVal),
+    /// target type, got value
+    BadType(String, ConstVal),
     ErroneousReferencedConstant(Box<ConstEvalErr>),
     CharCast(ConstInt),
+    Aggregate(Vec<ConstEvalErr>),
 }
 
 impl From<ConstMathErr> for ErrKind {
@@ -471,11 +474,12 @@ impl ConstEvalErr {
                 format!("mismatched types: expected `{}`, found `{}`",
                         expected, got.description()).into_cow()
             },
-            BadType(ref i) => format!("value of wrong type: {:?}", i).into_cow(),
+            BadType(ref ty, ref i) => format!("expected `{}`, found `{:?}`", ty, i).into_cow(),
             ErroneousReferencedConstant(_) => "could not evaluate referenced constant".into_cow(),
             CharCast(ref got) => {
                 format!("only `u8` can be cast as `char`, not `{}`", got.description()).into_cow()
             },
+            Aggregate(ref v) => format!("evaluation of {} fields failed", v.len()).into_cow(),
         }
     }
 }
@@ -771,9 +775,7 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                       signal!(e, UnimplementedConstVal("enum variants"));
                   }
               }
-              Def::Struct(..) => {
-                  ConstVal::Struct(e.id)
-              }
+              Def::Struct(did) => Struct(did, BTreeMap::new()),
               Def::Local(_, id) => {
                   debug!("Def::Local({:?}): {:?}", id, fn_args);
                   if let Some(val) = fn_args.and_then(|args| args.get(&id)) {
@@ -791,7 +793,7 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
           let callee_val = eval_const_expr_partial(tcx, callee, sub_ty_hint, fn_args)?;
           let did = match callee_val {
               Function(did) => did,
-              Struct(_) => signal!(e, UnimplementedConstVal("tuple struct constructors")),
+              Struct(..) => signal!(e, UnimplementedConstVal("tuple struct constructors")),
               callee => signal!(e, CallOn(callee)),
           };
           let (decl, result) = if let Some(fn_like) = lookup_const_fn_by_id(tcx, did) {
@@ -799,7 +801,6 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
           } else {
               signal!(e, NonConstPath)
           };
-          let result = result.as_ref().expect("const fn has no result expression");
           assert_eq!(decl.inputs.len(), args.len());
 
           let mut call_args = NodeMap();
@@ -816,7 +817,11 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
               assert!(old.is_none());
           }
           debug!("const call({:?})", call_args);
-          eval_const_expr_partial(tcx, &result, ty_hint, Some(&call_args))?
+          if let &Some(ref result) = result {
+              eval_const_expr_partial(tcx, &result, ty_hint, Some(&call_args))?
+          } else {
+              Tuple(None, Vec::new())
+          }
       },
       hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ety, lit.span) {
           Ok(val) => val,
@@ -825,12 +830,46 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
       hir::ExprBlock(ref block) => {
         match block.expr {
             Some(ref expr) => eval_const_expr_partial(tcx, &expr, ty_hint, fn_args)?,
-            None => signal!(e, UnimplementedConstVal("empty block")),
+            None => Tuple(None, Vec::new()), // unit value
         }
       }
       hir::ExprType(ref e, _) => eval_const_expr_partial(tcx, &e, ty_hint, fn_args)?,
-      hir::ExprTup(_) => Tuple(e.id),
-      hir::ExprStruct(..) => Struct(e.id),
+      hir::ExprTup(ref v) => {
+          let mut fields = Vec::with_capacity(v.len());
+          let mut errors = Vec::new();
+          for field in v {
+              match eval_const_expr_partial(tcx, field, ty_hint.erase_hint(), fn_args) {
+                  Ok(v) => fields.push(v),
+                  Err(e) => errors.push(e),
+              }
+          }
+          if !errors.is_empty() {
+              signal!(e, Aggregate(errors));
+          }
+          assert_eq!(fields.len(), v.len());
+          Tuple(None, fields)
+      },
+      hir::ExprStruct(_, _, Some(_)) => signal!(e, UnimplementedConstVal("struct base")),
+      hir::ExprStruct(_, ref fields, None) => {
+          let def_id = match tcx.def_map.borrow().get(&e.id).map(|def| def.full_def()) {
+              Some(Def::Struct(def_id)) => def_id,
+              Some(Def::Variant(..)) => signal!(e, UnimplementedConstVal("enums")),
+              _ => signal!(e, NonConstPath),
+          };
+          let mut new_fields = BTreeMap::new();
+          let mut errors = Vec::new();
+          for field in fields {
+              match eval_const_expr_partial(tcx, &field.expr, ty_hint.erase_hint(), fn_args) {
+                  Ok(f_val) => assert!(new_fields.insert(field.name.node, f_val).is_none()),
+                  Err(e) => errors.push(e),
+              }
+          }
+          if !errors.is_empty() {
+              signal!(e, Aggregate(errors));
+          }
+          assert_eq!(new_fields.len(), fields.len());
+          Struct(def_id, new_fields)
+      },
       hir::ExprIndex(ref arr, ref idx) => {
         if !tcx.sess.features.borrow().const_indexing {
             signal!(e, IndexOpFeatureGated);
@@ -845,21 +884,11 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         };
         assert_eq!(idx as usize as u64, idx);
         match arr {
-            Array(_, n) if idx >= n => signal!(e, IndexOutOfBounds),
-            Array(v, n) => if let hir::ExprVec(ref v) = tcx.map.expect_expr(v).node {
-                assert_eq!(n as usize as u64, n);
-                eval_const_expr_partial(tcx, &v[idx as usize], ty_hint, fn_args)?
-            } else {
-                bug!()
-            },
+            Array(ref v) if idx as usize >= v.len() => signal!(e, IndexOutOfBounds),
+            Array(ref v) => v[idx as usize].clone(),
 
             Repeat(_, n) if idx >= n => signal!(e, IndexOutOfBounds),
-            Repeat(elem, _) => eval_const_expr_partial(
-                tcx,
-                &tcx.map.expect_expr(elem),
-                ty_hint,
-                fn_args,
-            )?,
+            Repeat(elem, _) => *elem,
 
             ByteStr(ref data) if idx >= data.len() as u64 => signal!(e, IndexOutOfBounds),
             ByteStr(data) => {
@@ -872,11 +901,30 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             _ => signal!(e, IndexedNonVec),
         }
       }
-      hir::ExprVec(ref v) => Array(e.id, v.len() as u64),
-      hir::ExprRepeat(_, ref n) => {
+      hir::ExprVec(ref v) => {
+          let mut elems = Vec::with_capacity(v.len());
+          let mut errors = Vec::new();
+          for elem in v {
+              match eval_const_expr_partial(tcx, elem, ty_hint.erase_hint(), fn_args) {
+                  Ok(elem) => elems.push(elem),
+                  Err(e) => errors.push(e),
+              }
+          }
+          if !errors.is_empty() {
+              signal!(e, Aggregate(errors));
+          }
+          assert_eq!(elems.len(), v.len());
+          Array(elems)
+      },
+      hir::ExprRepeat(ref elem, ref n) => {
           let len_hint = ty_hint.checked_or(tcx.types.usize);
+          let val_hint = match ty_hint {
+              ExprTypeChecked => ExprTypeChecked,
+              UncheckedExprNoHint => UncheckedExprNoHint,
+              UncheckedExprHint(ty) => UncheckedExprHint(ty.sequence_element_type(tcx)),
+          };
           Repeat(
-              e.id,
+              box eval_const_expr_partial(tcx, elem, val_hint, fn_args)?,
               match eval_const_expr_partial(tcx, &n, len_hint, fn_args)? {
                   Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
                   Integral(_) => signal!(e, RepeatCountNotNatural),
@@ -886,40 +934,24 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
       },
       hir::ExprTupField(ref base, index) => {
         let base_hint = ty_hint.erase_hint();
-        let c = eval_const_expr_partial(tcx, base, base_hint, fn_args)?;
-        if let Tuple(tup_id) = c {
-            if let hir::ExprTup(ref fields) = tcx.map.expect_expr(tup_id).node {
-                if index.node < fields.len() {
-                    eval_const_expr_partial(tcx, &fields[index.node], ty_hint, fn_args)?
-                } else {
-                    signal!(e, TupleIndexOutOfBounds);
-                }
-            } else {
-                bug!()
-            }
-        } else {
-            signal!(base, ExpectedConstTuple);
+        match eval_const_expr_partial(tcx, base, base_hint, fn_args)? {
+            Tuple(_, ref v) if index.node >= v.len() => signal!(e, TupleIndexOutOfBounds),
+            Tuple(_, v) => v[index.node as usize].clone(),
+            _ => signal!(base, ExpectedConstTuple),
         }
       }
       hir::ExprField(ref base, field_name) => {
         let base_hint = ty_hint.erase_hint();
         // Get the base expression if it is a struct and it is constant
-        let c = eval_const_expr_partial(tcx, base, base_hint, fn_args)?;
-        if let Struct(struct_id) = c {
-            if let hir::ExprStruct(_, ref fields, _) = tcx.map.expect_expr(struct_id).node {
-                // Check that the given field exists and evaluate it
-                // if the idents are compared run-pass/issue-19244 fails
-                if let Some(f) = fields.iter().find(|f| f.name.node
-                                                     == field_name.node) {
-                    eval_const_expr_partial(tcx, &f.expr, ty_hint, fn_args)?
+        match eval_const_expr_partial(tcx, base, base_hint, fn_args)? {
+            Struct(_, fields) => {
+                if let Some(f) = fields.get(&field_name.node) {
+                    f.clone()
                 } else {
                     signal!(e, MissingStructField);
                 }
-            } else {
-                bug!()
-            }
-        } else {
-            signal!(base, ExpectedConstStruct);
+            },
+            _ => signal!(base, ExpectedConstStruct),
         }
       }
       hir::ExprAddrOf(..) => signal!(e, UnimplementedConstVal("address operator")),
@@ -996,7 +1028,8 @@ fn infer<'a, 'tcx>(i: ConstInt,
             let int_ty = tcx.enum_repr_type(hints.iter().next());
             infer(i, tcx, &int_ty.to_ty(tcx).sty)
         },
-        (_, i) => Err(BadType(ConstVal::Integral(i))),
+        (&ty::TyParam(_), i) => Ok(i),
+        (ty, i) => Err(BadType(ty.to_string(), ConstVal::Integral(i))),
     }
 }
 
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 1e7164a62c070..fd07439c43a3d 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -712,19 +712,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             ref sty => bug!("unexpected sty: {:?}", sty)
         },
         Def::Const(def_id) |
-        Def::AssociatedConst(def_id) => {
-            let substs = Some(cx.tcx.node_id_item_substs(expr.id).substs);
-            let tcx = cx.tcx.global_tcx();
-            if let Some((e, _)) = const_eval::lookup_const_by_id(tcx, def_id, substs) {
-                // FIXME ConstVal can't be yet used with adjustments, as they would be lost.
-                if !cx.tcx.tables.borrow().adjustments.contains_key(&e.id) {
-                    if let Some(v) = cx.try_const_eval_literal(e) {
-                        return ExprKind::Literal { literal: v };
-                    }
-                }
-            }
-            def_id
-        }
+        Def::AssociatedConst(def_id) => def_id,
 
         Def::Static(node_id, _) => return ExprKind::StaticRef {
             id: node_id,
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index fad6cfb7ae1aa..e5d2b00add767 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -90,21 +90,6 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn try_const_eval_literal(&mut self, e: &hir::Expr) -> Option<Literal<'tcx>> {
-        let hint = const_eval::EvalHint::ExprTypeChecked;
-        let tcx = self.tcx.global_tcx();
-        const_eval::eval_const_expr_partial(tcx, e, hint, None).ok().and_then(|v| {
-            match v {
-                // All of these contain local IDs, unsuitable for storing in MIR.
-                ConstVal::Struct(_) | ConstVal::Tuple(_) |
-                ConstVal::Array(..) | ConstVal::Repeat(..) |
-                ConstVal::Function(_) => None,
-
-                _ => Some(Literal::Value { value: v })
-            }
-        })
-    }
-
     pub fn trait_method(&mut self,
                         trait_def_id: DefId,
                         method_name: &str,
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index b1bb48aacee9f..9fce6e6fee8b7 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -30,7 +30,7 @@ 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, UnimplementedConstVal, MiscCatchAll, Math};
 use rustc_const_eval::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath};
-use rustc_const_eval::ErrKind::UnresolvedPath;
+use rustc_const_eval::ErrKind::{UnresolvedPath, Aggregate};
 use rustc_const_eval::EvalHint::ExprTypeChecked;
 use rustc_const_math::{ConstMathErr, Op};
 use rustc::hir::def::Def;
@@ -109,14 +109,32 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
             }
         }
         if let Err(err) = eval_const_expr_partial(self.tcx, expr, ExprTypeChecked, None) {
-            match err.kind {
-                UnimplementedConstVal(_) => {},
-                IndexOpFeatureGated => {},
-                ErroneousReferencedConstant(_) => {},
-                _ => self.tcx.sess.add_lint(CONST_ERR, expr.id, expr.span,
-                                         format!("constant evaluation error: {}. This will \
-                                                 become a HARD ERROR in the future",
-                                                 err.description())),
+            fn ignore(err: &ConstEvalErr) -> bool {
+                match err.kind {
+                    UnimplementedConstVal(_) => true,
+                    IndexOpFeatureGated => true,
+                    ErroneousReferencedConstant(_) => true,
+                    Aggregate(ref v) => v.iter().all(ignore),
+                    _ => false,
+                }
+            }
+            if !ignore(&err) {
+                if let Aggregate(ref v) = err.kind {
+                    for err in v {
+                        if !ignore(err) {
+                            self.tcx.sess.add_lint(CONST_ERR, expr.id, err.span,
+                                                   format!("constant evaluation error: {}. This \
+                                                            will become a HARD ERROR in the \
+                                                            future",
+                                                            err.description()));
+                        }
+                    }
+                } else {
+                    self.tcx.sess.add_lint(CONST_ERR, expr.id, err.span,
+                                           format!("constant evaluation error: {}. This will \
+                                                    become a HARD ERROR in the future",
+                                                    err.description()));
+                }
             }
         }
         self.with_mode(mode, |this| {
@@ -415,21 +433,37 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
         }
 
         if self.mode == Mode::Var && !self.qualif.intersects(ConstQualif::NOT_CONST) {
-            match eval_const_expr_partial(self.tcx, ex, ExprTypeChecked, None) {
-                Ok(_) => {}
-                Err(ConstEvalErr { kind: UnimplementedConstVal(_), ..}) |
-                Err(ConstEvalErr { kind: MiscCatchAll, ..}) |
-                Err(ConstEvalErr { kind: MiscBinaryOp, ..}) |
-                Err(ConstEvalErr { kind: NonConstPath, ..}) |
-                Err(ConstEvalErr { kind: UnresolvedPath, ..}) |
-                Err(ConstEvalErr { kind: ErroneousReferencedConstant(_), ..}) |
-                Err(ConstEvalErr { kind: Math(ConstMathErr::Overflow(Op::Shr)), ..}) |
-                Err(ConstEvalErr { kind: Math(ConstMathErr::Overflow(Op::Shl)), ..}) |
-                Err(ConstEvalErr { kind: IndexOpFeatureGated, ..}) => {},
-                Err(msg) => {
-                    self.tcx.sess.add_lint(CONST_ERR, ex.id,
-                                           msg.span,
-                                           msg.description().into_owned())
+            fn ignore(err: &ConstEvalErr) -> bool {
+                match err.kind {
+                    UnimplementedConstVal(_) |
+                    MiscCatchAll |
+                    MiscBinaryOp |
+                    NonConstPath |
+                    UnresolvedPath |
+                    ErroneousReferencedConstant(_) |
+                    Math(ConstMathErr::Overflow(Op::Shr)) |
+                    Math(ConstMathErr::Overflow(Op::Shl)) |
+                    IndexOpFeatureGated => true,
+                    Aggregate(ref v) => v.iter().all(ignore),
+                    _ => false,
+                }
+            }
+            if let Err(msg) = eval_const_expr_partial(self.tcx, ex, ExprTypeChecked, None) {
+                if !ignore(&msg) {
+                    if let Aggregate(ref v) = msg.kind {
+                        // report single errors for aggregate errors
+                        for msg in v {
+                            if !ignore(&msg) {
+                                self.tcx.sess.add_lint(CONST_ERR, ex.id,
+                                                       msg.span,
+                                                       msg.description().into_owned())
+                            }
+                        }
+                    } else {
+                        self.tcx.sess.add_lint(CONST_ERR, ex.id,
+                                               msg.span,
+                                               msg.description().into_owned())
+                    }
                 }
             }
         }
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index 039304ece60b0..b3c89708f5a4e 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -17,14 +17,14 @@ use rustc::infer::TransNormalize;
 use rustc::mir::repr as mir;
 use rustc::mir::tcx::LvalueTy;
 use rustc::traits;
-use rustc::ty::{self, Ty, TypeFoldable};
+use rustc::ty::{self, Ty, TypeFoldable, TyStruct, TyTuple};
 use rustc::ty::cast::{CastTy, IntTy};
 use rustc::ty::subst::Substs;
 use {abi, adt, base, Disr};
 use callee::Callee;
 use common::{self, BlockAndBuilder, CrateContext, const_get_elt, val_ty};
 use common::{C_array, C_bool, C_bytes, C_floating_f64, C_integral};
-use common::{C_null, C_struct, C_str_slice, C_undef, C_uint};
+use common::{C_null, C_struct, C_str_slice, C_undef, C_uint, C_vector};
 use consts::{self, ConstEvalFailure, TrueConst, to_const_int};
 use monomorphize::{self, Instance};
 use type_of;
@@ -82,10 +82,66 @@ impl<'tcx> Const<'tcx> {
             },
             ConstVal::Integral(Infer(v)) => C_integral(llty, v as u64, false),
             ConstVal::Integral(InferSigned(v)) => C_integral(llty, v as u64, true),
-            ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()),
+            ConstVal::Str(v) => C_str_slice(ccx, v),
             ConstVal::ByteStr(ref v) => consts::addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"),
-            ConstVal::Struct(_) | ConstVal::Tuple(_) |
-            ConstVal::Array(..) | ConstVal::Repeat(..) |
+            ConstVal::Struct(did, mut field_values) => {
+                let repr = adt::represent_type(ccx, ty);
+                let substs = match ty.sty {
+                    TyStruct(_, substs) => substs,
+                    _ => bug!(),
+                };
+                let mut trans_fields = Vec::with_capacity(field_values.len());
+                let adt_def = ty.ty_adt_def().unwrap().struct_variant();
+                assert_eq!(adt_def.did, did);
+                for field in &adt_def.fields {
+                    if let Some(value) = field_values.remove(&field.name) {
+                        let field_ty = field.ty(ccx.tcx(), substs);
+                        let value = Self::from_constval(ccx, value, field_ty);
+                        trans_fields.push(value.llval);
+                    } else {
+                        bug!("trans knows struct fields that const doesn't");
+                    }
+                }
+                // FIXME: check that all elements of `field_values` have been translated
+                if ty.is_simd() {
+                    C_vector(&trans_fields)
+                } else {
+                    adt::trans_const(ccx, &*repr, adt_def.disr_val.into(), &trans_fields)
+                }
+            },
+            ConstVal::Tuple(Some(_), _) => unimplemented!(),
+            ConstVal::Tuple(None, field_values) => {
+                let repr = adt::represent_type(ccx, ty);
+                let field_types = match ty.sty {
+                    TyTuple(types) => types,
+                    _ => bug!(),
+                };
+                let mut trans_fields = Vec::with_capacity(field_values.len());
+                for (f_val, f_ty) in field_values.into_iter().zip(field_types) {
+                    let value = Self::from_constval(ccx, f_val, f_ty);
+                    trans_fields.push(value.llval);
+                }
+                if ty.is_simd() {
+                    C_vector(&trans_fields)
+                } else {
+                    adt::trans_const(ccx, &*repr, Disr(0), &trans_fields)
+                }
+            },
+            ConstVal::Repeat(val, n) => {
+                let val_ty = ty.sequence_element_type(ccx.tcx());
+                let ll_val_ty = type_of::type_of(ccx, val_ty);
+                assert_eq!(n as usize as u64, n);
+                let trans_fields = vec![Self::from_constval(ccx, *val, val_ty).llval; n as usize];
+                C_array(ll_val_ty, &trans_fields)
+            },
+            ConstVal::Array(vals) => {
+                let val_ty = ty.sequence_element_type(ccx.tcx());
+                let ll_val_ty = type_of::type_of(ccx, val_ty);
+                let trans_fields = vals.into_iter()
+                                       .map(|val| Self::from_constval(ccx, val, val_ty).llval)
+                                       .collect::<Vec<_>>();
+                C_array(ll_val_ty, &trans_fields)
+            },
             ConstVal::Function(_) => {
                 bug!("MIR must not use {:?} (which refers to a local ID)", cv)
             }
diff --git a/src/test/compile-fail/const-eval-overflow.rs b/src/test/compile-fail/const-eval-overflow.rs
index 96013551ef492..7efe309484579 100644
--- a/src/test/compile-fail/const-eval-overflow.rs
+++ b/src/test/compile-fail/const-eval-overflow.rs
@@ -10,6 +10,7 @@
 
 #![feature(rustc_attrs)]
 #![allow(unused_imports)]
+#![allow(const_err)]
 
 // Note: the relevant lint pass here runs before some of the constant
 // evaluation below (e.g. that performed by trans and llvm), so if you
diff --git a/src/test/compile-fail/const-eval-overflow0.rs b/src/test/compile-fail/const-eval-overflow0.rs
index 7db7de9cee30c..e7153641f47c5 100644
--- a/src/test/compile-fail/const-eval-overflow0.rs
+++ b/src/test/compile-fail/const-eval-overflow0.rs
@@ -20,67 +20,67 @@ use std::{i8, i16, i32, i64, isize};
 use std::{u8, u16, u32, u64, usize};
 
 const VALS_I8: (i8, i8, i8, i8) =
-    (-i8::MIN,
-     i8::MIN - 1,
-     i8::MAX + 1,
-     i8::MIN * 2,
+    (-i8::MIN, //~WARN const_err
+     i8::MIN - 1, //~WARN const_err
+     i8::MAX + 1, //~WARN const_err
+     i8::MIN * 2, //~WARN const_err
      );
 
 const VALS_I16: (i16, i16, i16, i16) =
-    (-i16::MIN,
-     i16::MIN - 1,
-     i16::MAX + 1,
-     i16::MIN * 2,
+    (-i16::MIN, //~WARN const_err
+     i16::MIN - 1, //~WARN const_err
+     i16::MAX + 1, //~WARN const_err
+     i16::MIN * 2, //~WARN const_err
      );
 
 const VALS_I32: (i32, i32, i32, i32) =
-    (-i32::MIN,
-     i32::MIN - 1,
-     i32::MAX + 1,
-     i32::MIN * 2,
+    (-i32::MIN, //~WARN const_err
+     i32::MIN - 1, //~WARN const_err
+     i32::MAX + 1, //~WARN const_err
+     i32::MIN * 2, //~WARN const_err
      );
 
 const VALS_I64: (i64, i64, i64, i64) =
-    (-i64::MIN,
-     i64::MIN - 1,
-     i64::MAX + 1,
-     i64::MAX * 2,
+    (-i64::MIN, //~WARN const_err
+     i64::MIN - 1, //~WARN const_err
+     i64::MAX + 1, //~WARN const_err
+     i64::MAX * 2, //~WARN const_err
      );
 
 const VALS_U8: (u8, u8, u8, u8) =
     (-u8::MIN,
      //~^ ERROR unary negation of unsigned integer
      //~| HELP use a cast or the `!` operator
-     u8::MIN - 1,
-     u8::MAX + 1,
-     u8::MAX * 2,
+     u8::MIN - 1, //~WARN const_err
+     u8::MAX + 1, //~WARN const_err
+     u8::MAX * 2, //~WARN const_err
      );
 
 const VALS_U16: (u16, u16, u16, u16) =
     (-u16::MIN,
      //~^ ERROR unary negation of unsigned integer
      //~| HELP use a cast or the `!` operator
-     u16::MIN - 1,
-     u16::MAX + 1,
-     u16::MAX * 2,
+     u16::MIN - 1, //~WARN const_err
+     u16::MAX + 1, //~WARN const_err
+     u16::MAX * 2, //~WARN const_err
      );
 
 const VALS_U32: (u32, u32, u32, u32) =
     (-u32::MIN,
      //~^ ERROR unary negation of unsigned integer
      //~| HELP use a cast or the `!` operator
-     u32::MIN - 1,
-     u32::MAX + 1,
-     u32::MAX * 2,
+     u32::MIN - 1, //~WARN const_err
+     u32::MAX + 1, //~WARN const_err
+     u32::MAX * 2, //~WARN const_err
      );
 
 const VALS_U64: (u64, u64, u64, u64) =
     (-u64::MIN,
      //~^ ERROR unary negation of unsigned integer
      //~| HELP use a cast or the `!` operator
-     u64::MIN - 1,
-     u64::MAX + 1,
-     u64::MAX * 2,
+     u64::MIN - 1, //~WARN const_err
+     u64::MAX + 1, //~WARN const_err
+     u64::MAX * 2, //~WARN const_err
      );
 
 fn main() {
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 4567cd4a74bb2..cb55e81eb9f21 100644
--- a/src/test/compile-fail/const-pattern-not-const-evaluable.rs
+++ b/src/test/compile-fail/const-pattern-not-const-evaluable.rs
@@ -17,8 +17,7 @@ enum Cake {
 use Cake::*;
 
 const BOO: (Cake, Cake) = (Marmor, BlackForest);
-//~^ ERROR: constant evaluation error: unimplemented constant expression: enum variants [E0471]
-const FOO: Cake = BOO.1;
+const FOO: Cake = BOO.1; //~ERROR could not evaluate referenced constant
 
 const fn foo() -> Cake {
     Marmor //~ ERROR: constant evaluation error: unimplemented constant expression: enum variants
diff --git a/src/test/compile-fail/issue-17718-const-borrow.rs b/src/test/compile-fail/issue-17718-const-borrow.rs
index ec6d1141c1a05..88967b7669bfb 100644
--- a/src/test/compile-fail/issue-17718-const-borrow.rs
+++ b/src/test/compile-fail/issue-17718-const-borrow.rs
@@ -23,4 +23,7 @@ const E: &'static UnsafeCell<usize> = &D.a;
 const F: &'static C = &D;
 //~^ ERROR: cannot borrow a constant which contains interior mutability
 
+const G: &'static UnsafeCell<usize> = &UnsafeCell::new(42);
+//~^ ERROR: cannot borrow a constant which contains interior mutability
+
 fn main() {}
diff --git a/src/test/run-pass/const-fn.rs b/src/test/run-pass/const-fn.rs
index 562040dc5620b..3b13cc661f6ee 100644
--- a/src/test/run-pass/const-fn.rs
+++ b/src/test/run-pass/const-fn.rs
@@ -11,6 +11,7 @@
 // A very basic test of const fn functionality.
 
 #![feature(const_fn, const_indexing)]
+#![deny(const_err)]
 
 const fn add(x: u32, y: u32) -> u32 {
     x + y
@@ -32,6 +33,18 @@ const fn generic_arr<T: Copy>(t: [T; 1]) -> T {
     t[0]
 }
 
+pub const fn test() {}
+const X: () = test();
+
+const fn f(_: ()) -> usize { 1 }
+
+const fn g(x: usize) -> A {
+    A { field: x }
+}
+struct A {
+    field: usize,
+}
+
 const SUM: u32 = add(44, 22);
 const DIFF: u32 = sub(44, 22);
 const DIV: u32 = unsafe{div(44, 22)};
@@ -46,4 +59,6 @@ fn main() {
     let _: [&'static str; sub(100, 99) as usize] = ["hi"];
     let _: [&'static str; generic(1)] = ["hi"];
     let _: [&'static str; generic_arr([1])] = ["hi"];
+    let _: [&'static str; f({})] = ["hi"];
+    let _ = [0; g(5).field];
 }
diff --git a/src/test/run-pass/issue-28189.rs b/src/test/run-pass/issue-28189.rs
index 0e624a778583d..032b809bfcafe 100644
--- a/src/test/run-pass/issue-28189.rs
+++ b/src/test/run-pass/issue-28189.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-struct S<T>(T) where [T; (||{}, 1).1]: Copy;
+struct S<T>(T) where [T; ((), 1).1]: Copy;
 
 fn main() {