about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-03-07 00:27:07 +0000
committerbors <bors@rust-lang.org>2019-03-07 00:27:07 +0000
commit88f755f8a84df1d9e6b17cf10c96ae8b93481b2e (patch)
tree140a26d5dd27f9cec68ddef6a41e3fade7d46bd7
parentf22dca0a1bef4141e75326caacc3cd59f3d5be8e (diff)
parentde4478af91765999f51b2950bea16686ee4cd60a (diff)
downloadrust-88f755f8a84df1d9e6b17cf10c96ae8b93481b2e.tar.gz
rust-88f755f8a84df1d9e6b17cf10c96ae8b93481b2e.zip
Auto merge of #58583 - varkor:const-generics-ty, r=oli-obk
Add const generics to ty (and transitive dependencies)

Split out from #53645. This work is a collaborative effort with @yodaldevoid.

There are a number of stubs. Some I plan to leave for the next PRs (e.g. `infer` and `rustdoc`). Others I can either fix up in this PR, or as follow ups (which would avoid the time-consuming rebasing).

It was a little hard to split this up, as so much depends on ty and friends. Apologies for the large diff.

r? @eddyb
-rw-r--r--src/librustc/ich/impls_ty.rs27
-rw-r--r--src/librustc/infer/canonical/mod.rs3
-rw-r--r--src/librustc/infer/canonical/query_response.rs15
-rw-r--r--src/librustc/infer/combine.rs2
-rw-r--r--src/librustc/infer/error_reporting/mod.rs16
-rw-r--r--src/librustc/infer/mod.rs13
-rw-r--r--src/librustc/infer/nll_relate/mod.rs4
-rw-r--r--src/librustc/infer/opaque_types/mod.rs11
-rw-r--r--src/librustc/infer/outlives/obligations.rs20
-rw-r--r--src/librustc/middle/resolve_lifetime.rs2
-rw-r--r--src/librustc/mir/interpret/value.rs10
-rw-r--r--src/librustc/traits/error_reporting.rs3
-rw-r--r--src/librustc/traits/mod.rs3
-rw-r--r--src/librustc/traits/object_safety.rs3
-rw-r--r--src/librustc/traits/on_unimplemented.rs3
-rw-r--r--src/librustc/ty/context.rs100
-rw-r--r--src/librustc/ty/flags.rs32
-rw-r--r--src/librustc/ty/fold.rs19
-rw-r--r--src/librustc/ty/mod.rs35
-rw-r--r--src/librustc/ty/relate.rs3
-rw-r--r--src/librustc/ty/structural_impls.rs22
-rw-r--r--src/librustc/ty/sty.rs81
-rw-r--r--src/librustc/ty/subst.rs116
-rw-r--r--src/librustc/ty/util.rs20
-rw-r--r--src/librustc/util/ppaux.rs70
-rw-r--r--src/librustc_codegen_llvm/callee.rs2
-rw-r--r--src/librustc_codegen_ssa/back/symbol_export.rs2
-rw-r--r--src/librustc_codegen_ssa/mir/operand.rs2
-rw-r--r--src/librustc_codegen_utils/symbol_names.rs2
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs9
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs5
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs2
-rw-r--r--src/librustc_mir/hair/cx/expr.rs29
-rw-r--r--src/librustc_mir/interpret/operand.rs5
-rw-r--r--src/librustc_mir/monomorphize/collector.rs27
-rw-r--r--src/librustc_mir/monomorphize/item.rs52
-rw-r--r--src/librustc_mir/monomorphize/partitioning.rs2
-rw-r--r--src/librustc_mir/shim.rs9
-rw-r--r--src/librustc_mir/transform/check_unsafety.rs5
-rw-r--r--src/librustc_mir/transform/inline.rs2
-rw-r--r--src/librustc_privacy/lib.rs10
-rw-r--r--src/librustc_traits/chalk_context/mod.rs13
-rw-r--r--src/librustc_typeck/astconv.rs85
-rw-r--r--src/librustc_typeck/check/closure.rs10
-rw-r--r--src/librustc_typeck/check/compare_method.rs113
-rw-r--r--src/librustc_typeck/check/dropck.rs3
-rw-r--r--src/librustc_typeck/check/method/confirm.rs3
-rw-r--r--src/librustc_typeck/check/method/mod.rs4
-rw-r--r--src/librustc_typeck/check/method/probe.rs10
-rw-r--r--src/librustc_typeck/check/mod.rs22
-rw-r--r--src/librustc_typeck/check/regionck.rs22
-rw-r--r--src/librustc_typeck/check/wfcheck.rs59
-rw-r--r--src/librustc_typeck/collect.rs235
-rw-r--r--src/librustc_typeck/constrained_type_params.rs15
-rw-r--r--src/librustc_typeck/diagnostics.rs9
-rw-r--r--src/librustc_typeck/impl_wf_check.rs11
-rw-r--r--src/librustc_typeck/outlives/mod.rs22
-rw-r--r--src/librustc_typeck/outlives/utils.rs4
-rw-r--r--src/librustc_typeck/variance/constraints.rs49
-rw-r--r--src/librustdoc/clean/mod.rs9
-rw-r--r--src/librustdoc/core.rs3
-rw-r--r--src/test/ui/const-generics/const-expression-parameter.rs11
-rw-r--r--src/test/ui/const-generics/const-expression-parameter.stderr16
-rw-r--r--src/test/ui/const-generics/const-fn-with-const-param.rs1
-rw-r--r--src/test/ui/const-generics/const-fn-with-const-param.stderr9
-rw-r--r--src/test/ui/const-generics/const-param-before-other-params.rs4
-rw-r--r--src/test/ui/const-generics/const-param-before-other-params.stderr18
-rw-r--r--src/test/ui/const-generics/const-param-from-outer-fn.rs1
-rw-r--r--src/test/ui/const-generics/const-param-from-outer-fn.stderr11
-rw-r--r--src/test/ui/const-generics/const-parameter-uppercase-lint.rs4
-rw-r--r--src/test/ui/const-generics/const-parameter-uppercase-lint.stderr17
-rw-r--r--src/test/ui/derives/deriving-with-repr-packed.stderr4
-rw-r--r--src/test/ui/feature-gates/feature-gate-const_generics.rs2
-rw-r--r--src/test/ui/feature-gates/feature-gate-const_generics.stderr16
74 files changed, 1201 insertions, 412 deletions
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index f77a88128f2..21988de9018 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -74,6 +74,7 @@ for ty::subst::UnpackedKind<'gcx> {
         match self {
             ty::subst::UnpackedKind::Lifetime(lt) => lt.hash_stable(hcx, hasher),
             ty::subst::UnpackedKind::Type(ty) => ty.hash_stable(hcx, hasher),
+            ty::subst::UnpackedKind::Const(ct) => ct.hash_stable(hcx, hasher),
         }
     }
 }
@@ -134,6 +135,15 @@ impl<'a> HashStable<StableHashingContext<'a>> for ty::RegionVid {
     }
 }
 
+impl<'gcx, 'tcx> HashStable<StableHashingContext<'gcx>> for ty::ConstVid<'tcx> {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hasher: &mut StableHasher<W>) {
+        self.index.hash_stable(hcx, hasher);
+    }
+}
+
 impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::BoundVar {
     #[inline]
     fn hash_stable<W: StableHasherResult>(&self,
@@ -297,6 +307,14 @@ impl<'a> HashStable<StableHashingContext<'a>> for ty::VariantFlags {
     }
 }
 
+impl_stable_hash_for!(
+    impl<'tcx> for enum ty::InferConst<'tcx> [ ty::InferConst ] {
+        Var(vid),
+        Fresh(i),
+        Canonical(debruijn, var),
+    }
+);
+
 impl_stable_hash_for!(enum ty::VariantDiscr {
     Explicit(def_id),
     Relative(distance)
@@ -310,11 +328,14 @@ impl_stable_hash_for!(struct ty::FieldDef {
 
 impl_stable_hash_for!(
     impl<'tcx> for enum mir::interpret::ConstValue<'tcx> [ mir::interpret::ConstValue ] {
+        Param(param),
+        Infer(infer),
         Scalar(val),
         Slice(a, b),
         ByRef(ptr, alloc),
     }
 );
+
 impl_stable_hash_for!(struct crate::mir::interpret::RawConst<'tcx> {
     alloc_id,
     ty,
@@ -518,6 +539,7 @@ impl_stable_hash_for!(struct ty::GenericParamDef {
 impl_stable_hash_for!(enum ty::GenericParamDefKind {
     Lifetime,
     Type { has_default, object_lifetime_default, synthetic },
+    Const,
 });
 
 impl_stable_hash_for!(
@@ -736,6 +758,11 @@ for ty::FloatVid
     }
 }
 
+impl_stable_hash_for!(struct ty::ParamConst {
+    index,
+    name
+});
+
 impl_stable_hash_for!(struct ty::ParamTy {
     idx,
     name
diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc/infer/canonical/mod.rs
index 613e153ae33..0d067d1de85 100644
--- a/src/librustc/infer/canonical/mod.rs
+++ b/src/librustc/infer/canonical/mod.rs
@@ -443,6 +443,9 @@ impl<'tcx> CanonicalVarValues<'tcx> {
                     UnpackedKind::Lifetime(..) => tcx.mk_region(
                         ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(i))
                     ).into(),
+                    UnpackedKind::Const(..) => {
+                        unimplemented!() // FIXME(const_generics)
+                    }
                 })
                 .collect()
         }
diff --git a/src/librustc/infer/canonical/query_response.rs b/src/librustc/infer/canonical/query_response.rs
index aef0152b6ed..008882fd500 100644
--- a/src/librustc/infer/canonical/query_response.rs
+++ b/src/librustc/infer/canonical/query_response.rs
@@ -315,6 +315,10 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
                     obligations.extend(ok.into_obligations());
                 }
 
+                (UnpackedKind::Const(..), UnpackedKind::Const(..)) => {
+                    unimplemented!() // FIXME(const_generics)
+                }
+
                 _ => {
                     bug!(
                         "kind mismatch, cannot unify {:?} and {:?}",
@@ -473,6 +477,9 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
                         opt_values[br.assert_bound_var()] = Some(*original_value);
                     }
                 }
+                UnpackedKind::Const(..) => {
+                    unimplemented!() // FIXME(const_generics)
+                }
             }
         }
 
@@ -568,6 +575,11 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
                                 ty::OutlivesPredicate(t1, r2)
                             )
                         ),
+                        UnpackedKind::Const(..) => {
+                            // Consts cannot outlive one another, so we don't expect to
+                            // ecounter this branch.
+                            span_bug!(cause.span, "unexpected const outlives {:?}", constraint);
+                        }
                     }
                 )
             })
@@ -602,6 +614,9 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
                         obligations
                             .extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations());
                     }
+                    (UnpackedKind::Const(..), UnpackedKind::Const(..)) => {
+                        unimplemented!() // FIXME(const_generics)
+                    }
                     _ => {
                         bug!("kind mismatch, cannot unify {:?} and {:?}", value1, value2,);
                     }
diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs
index 6ef902a47dc..885b439ef1c 100644
--- a/src/librustc/infer/combine.rs
+++ b/src/librustc/infer/combine.rs
@@ -449,7 +449,7 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, '
 
                             let origin = *variables.var_origin(vid);
                             let new_var_id = variables.new_var(self.for_universe, false, origin);
-                            let u = self.tcx().mk_var(new_var_id);
+                            let u = self.tcx().mk_ty_var(new_var_id);
                             debug!("generalize: replacing original vid={:?} with new={:?}",
                                    vid, u);
                             return Ok(u);
diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
index 3dace2f2e89..c7936534aad 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -691,17 +691,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     ) -> SubstsRef<'tcx> {
         let generics = self.tcx.generics_of(def_id);
         let mut num_supplied_defaults = 0;
-        let mut type_params = generics
-            .params
-            .iter()
-            .rev()
-            .filter_map(|param| match param.kind {
-                ty::GenericParamDefKind::Lifetime => None,
-                ty::GenericParamDefKind::Type { has_default, .. } => {
-                    Some((param.def_id, has_default))
-                }
-            })
-            .peekable();
+        let mut type_params = generics.params.iter().rev().filter_map(|param| match param.kind {
+            ty::GenericParamDefKind::Lifetime => None,
+            ty::GenericParamDefKind::Type { has_default, .. } => Some((param.def_id, has_default)),
+            ty::GenericParamDefKind::Const => None, // FIXME(const_generics:defaults)
+        }).peekable();
         let has_default = {
             let has_default = type_params.peek().map(|(_, has_default)| has_default);
             *has_default.unwrap_or(&false)
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 84ad742d3c9..cc1c439f3bd 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -656,7 +656,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         type_variables
             .unsolved_variables()
             .into_iter()
-            .map(|t| self.tcx.mk_var(t))
+            .map(|t| self.tcx.mk_ty_var(t))
             .chain(
                 (0..int_unification_table.len())
                     .map(|i| ty::IntVid { index: i as u32 })
@@ -981,7 +981,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
-        self.tcx.mk_var(self.next_ty_var_id(false, origin))
+        self.tcx.mk_ty_var(self.next_ty_var_id(false, origin))
     }
 
     pub fn next_ty_var_in_universe(
@@ -992,11 +992,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         let vid = self.type_variables
             .borrow_mut()
             .new_var(universe, false, origin);
-        self.tcx.mk_var(vid)
+        self.tcx.mk_ty_var(vid)
     }
 
     pub fn next_diverging_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
-        self.tcx.mk_var(self.next_ty_var_id(true, origin))
+        self.tcx.mk_ty_var(self.next_ty_var_id(true, origin))
     }
 
     pub fn next_int_var_id(&self) -> IntVid {
@@ -1081,7 +1081,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                     TypeVariableOrigin::TypeParameterDefinition(span, param.name),
                 );
 
-                self.tcx.mk_var(ty_var_id).into()
+                self.tcx.mk_ty_var(ty_var_id).into()
+            }
+            GenericParamDefKind::Const { .. } => {
+                unimplemented!() // FIXME(const_generics)
             }
         }
     }
diff --git a/src/librustc/infer/nll_relate/mod.rs b/src/librustc/infer/nll_relate/mod.rs
index f37e24b292e..7140af36acb 100644
--- a/src/librustc/infer/nll_relate/mod.rs
+++ b/src/librustc/infer/nll_relate/mod.rs
@@ -310,7 +310,7 @@ where
             ty::Projection(projection_ty)
                 if D::normalization() == NormalizationStrategy::Lazy =>
             {
-                return Ok(self.relate_projection_ty(projection_ty, self.infcx.tcx.mk_var(vid)));
+                return Ok(self.relate_projection_ty(projection_ty, self.infcx.tcx.mk_ty_var(vid)));
             }
 
             _ => (),
@@ -764,7 +764,7 @@ where
                             // the universe `_universe`.
                             let new_var_id = variables.new_var(self.universe, false, origin);
 
-                            let u = self.tcx().mk_var(new_var_id);
+                            let u = self.tcx().mk_ty_var(new_var_id);
                             debug!(
                                 "generalize: replacing original vid={:?} with new={:?}",
                                 vid,
diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs
index 159bc1ceae2..1b7ecc7c3a6 100644
--- a/src/librustc/infer/opaque_types/mod.rs
+++ b/src/librustc/infer/opaque_types/mod.rs
@@ -381,10 +381,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                         substs,
                         item_def_id: _,
                     }) => {
-                        for r in substs.regions() {
-                            bound_region(r);
+                        for k in substs {
+                            match k.unpack() {
+                                UnpackedKind::Lifetime(lt) => bound_region(lt),
+                                UnpackedKind::Type(ty) => types.push(ty),
+                                UnpackedKind::Const(_) => {
+                                    // Const parameters don't impose constraints.
+                                }
+                            }
                         }
-                        types.extend(substs.types());
                     }
 
                     Component::EscapingProjection(more_components) => {
diff --git a/src/librustc/infer/outlives/obligations.rs b/src/librustc/infer/outlives/obligations.rs
index bbda3d2fdbf..ee660328485 100644
--- a/src/librustc/infer/outlives/obligations.rs
+++ b/src/librustc/infer/outlives/obligations.rs
@@ -67,6 +67,7 @@ use crate::hir;
 use crate::traits::ObligationCause;
 use crate::ty::outlives::Component;
 use crate::ty::{self, Region, Ty, TyCtxt, TypeFoldable};
+use crate::ty::subst::UnpackedKind;
 
 impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
     /// Registers that the given region obligation must be resolved
@@ -430,13 +431,18 @@ where
         if approx_env_bounds.is_empty() && trait_bounds.is_empty() && needs_infer {
             debug!("projection_must_outlive: no declared bounds");
 
-            for component_ty in projection_ty.substs.types() {
-                self.type_must_outlive(origin.clone(), component_ty, region);
-            }
-
-            for r in projection_ty.substs.regions() {
-                self.delegate
-                    .push_sub_region_constraint(origin.clone(), region, r);
+            for k in projection_ty.substs {
+                match k.unpack() {
+                    UnpackedKind::Lifetime(lt) => {
+                        self.delegate.push_sub_region_constraint(origin.clone(), region, lt);
+                    }
+                    UnpackedKind::Type(ty) => {
+                        self.type_must_outlive(origin.clone(), ty, region);
+                    }
+                    UnpackedKind::Const(_) => {
+                        // Const parameters don't impose constraints.
+                    }
+                }
             }
 
             return;
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 2618d0874cb..d2bec1070f9 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -1974,7 +1974,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                                     object_lifetime_default,
                                     ..
                                 } => Some(object_lifetime_default),
-                                GenericParamDefKind::Lifetime => None,
+                                GenericParamDefKind::Lifetime | GenericParamDefKind::Const => None,
                             })
                             .collect()
                     })
diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs
index 956182fc8b2..dbbeda3e578 100644
--- a/src/librustc/mir/interpret/value.rs
+++ b/src/librustc/mir/interpret/value.rs
@@ -1,6 +1,6 @@
 use std::fmt;
 
-use crate::ty::{Ty, layout::{HasDataLayout, Size}};
+use crate::ty::{Ty, InferConst, ParamConst, layout::{HasDataLayout, Size}};
 
 use super::{EvalResult, Pointer, PointerArithmetic, Allocation, AllocId, sign_extend, truncate};
 
@@ -17,6 +17,12 @@ pub struct RawConst<'tcx> {
 /// match the `LocalState` optimizations for easy conversions between `Value` and `ConstValue`.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)]
 pub enum ConstValue<'tcx> {
+    /// A const generic parameter.
+    Param(ParamConst),
+
+    /// Infer the value of the const.
+    Infer(InferConst<'tcx>),
+
     /// Used only for types with `layout::abi::Scalar` ABI and ZSTs.
     ///
     /// Not using the enum `Value` to encode that this must not be `Undef`.
@@ -43,6 +49,8 @@ impl<'tcx> ConstValue<'tcx> {
     #[inline]
     pub fn try_to_scalar(&self) -> Option<Scalar> {
         match *self {
+            ConstValue::Param(_) |
+            ConstValue::Infer(_) |
             ConstValue::ByRef(..) |
             ConstValue::Slice(..) => None,
             ConstValue::Scalar(val) => Some(val),
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 3eb49092fed..322e384e13e 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -389,7 +389,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
         for param in generics.params.iter() {
             let value = match param.kind {
-                GenericParamDefKind::Type {..} => {
+                GenericParamDefKind::Type { .. } |
+                GenericParamDefKind::Const => {
                     trait_ref.substs[param.index as usize].to_string()
                 },
                 GenericParamDefKind::Lifetime => continue,
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index ee7893a27de..32bb7f18693 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -1010,7 +1010,8 @@ fn vtable_methods<'a, 'tcx>(
                     InternalSubsts::for_item(tcx, def_id, |param, _|
                         match param.kind {
                             GenericParamDefKind::Lifetime => tcx.types.re_erased.into(),
-                            GenericParamDefKind::Type {..} => {
+                            GenericParamDefKind::Type { .. } |
+                            GenericParamDefKind::Const => {
                                 trait_ref.substs[param.index as usize]
                             }
                         }
diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs
index b2079c25169..e7a5138e689 100644
--- a/src/librustc/traits/object_safety.rs
+++ b/src/librustc/traits/object_safety.rs
@@ -310,7 +310,8 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
         }
 
         // We can't monomorphize things like `fn foo<A>(...)`.
-        if self.generics_of(method.def_id).own_counts().types != 0 {
+        let own_counts = self.generics_of(method.def_id).own_counts();
+        if own_counts.types + own_counts.consts != 0 {
             return Some(MethodViolationCode::Generic);
         }
 
diff --git a/src/librustc/traits/on_unimplemented.rs b/src/librustc/traits/on_unimplemented.rs
index f61c32614cc..c86fd0d52b9 100644
--- a/src/librustc/traits/on_unimplemented.rs
+++ b/src/librustc/traits/on_unimplemented.rs
@@ -280,7 +280,8 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString {
         let generics = tcx.generics_of(trait_ref.def_id);
         let generic_map = generics.params.iter().filter_map(|param| {
             let value = match param.kind {
-                GenericParamDefKind::Type {..} => {
+                GenericParamDefKind::Type { .. } |
+                GenericParamDefKind::Const => {
                     trait_ref.substs[param.index as usize].to_string()
                 },
                 GenericParamDefKind::Lifetime => return None
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 3c63dcb9ef3..f6e6067bb6f 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -21,8 +21,8 @@ use crate::middle::lang_items;
 use crate::middle::resolve_lifetime::{self, ObjectLifetimeDefault};
 use crate::middle::stability;
 use crate::mir::{self, Mir, interpret, ProjectionKind};
-use crate::mir::interpret::Allocation;
-use crate::ty::subst::{Kind, InternalSubsts, Subst, SubstsRef};
+use crate::mir::interpret::{ConstValue, Allocation};
+use crate::ty::subst::{Kind, InternalSubsts, SubstsRef, Subst};
 use crate::ty::ReprOptions;
 use crate::traits;
 use crate::traits::{Clause, Clauses, GoalKind, Goal, Goals};
@@ -31,8 +31,9 @@ use crate::ty::{TyS, TyKind, List};
 use crate::ty::{AdtKind, AdtDef, ClosureSubsts, GeneratorSubsts, Region, Const, LazyConst};
 use crate::ty::{PolyFnSig, InferTy, ParamTy, ProjectionTy, ExistentialPredicate, Predicate};
 use crate::ty::RegionKind;
-use crate::ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid};
+use crate::ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid, ConstVid};
 use crate::ty::TyKind::*;
+use crate::ty::{InferConst, ParamConst};
 use crate::ty::GenericParamDefKind;
 use crate::ty::layout::{LayoutDetails, TargetDataLayout, VariantIdx};
 use crate::ty::query;
@@ -872,6 +873,18 @@ impl CanonicalUserType<'gcx> {
                             }
                             _ => false,
                         },
+
+                        UnpackedKind::Const(ct) => match ct {
+                            ty::LazyConst::Evaluated(ty::Const {
+                                val: ConstValue::Infer(InferConst::Canonical(debruijn, b)),
+                                ..
+                            }) => {
+                                // We only allow a `ty::INNERMOST` index in substitutions.
+                                assert_eq!(*debruijn, ty::INNERMOST);
+                                cvar == *b
+                            }
+                            _ => false,
+                        },
                     }
                 })
             },
@@ -2120,15 +2133,19 @@ macro_rules! sty_debug_print {
             #[derive(Copy, Clone)]
             struct DebugStat {
                 total: usize,
-                region_infer: usize,
+                lt_infer: usize,
                 ty_infer: usize,
-                both_infer: usize,
+                ct_infer: usize,
+                all_infer: usize,
             }
 
             pub fn go(tcx: TyCtxt<'_, '_, '_>) {
                 let mut total = DebugStat {
                     total: 0,
-                    region_infer: 0, ty_infer: 0, both_infer: 0,
+                    lt_infer: 0,
+                    ty_infer: 0,
+                    ct_infer: 0,
+                    all_infer: 0,
                 };
                 $(let mut $variant = total;)*
 
@@ -2139,31 +2156,35 @@ macro_rules! sty_debug_print {
                         ty::Error => /* unimportant */ continue,
                         $(ty::$variant(..) => &mut $variant,)*
                     };
-                    let region = t.flags.intersects(ty::TypeFlags::HAS_RE_INFER);
+                    let lt = t.flags.intersects(ty::TypeFlags::HAS_RE_INFER);
                     let ty = t.flags.intersects(ty::TypeFlags::HAS_TY_INFER);
+                    let ct = t.flags.intersects(ty::TypeFlags::HAS_CT_INFER);
 
                     variant.total += 1;
                     total.total += 1;
-                    if region { total.region_infer += 1; variant.region_infer += 1 }
+                    if lt { total.lt_infer += 1; variant.lt_infer += 1 }
                     if ty { total.ty_infer += 1; variant.ty_infer += 1 }
-                    if region && ty { total.both_infer += 1; variant.both_infer += 1 }
+                    if ct { total.ct_infer += 1; variant.ct_infer += 1 }
+                    if lt && ty && ct { total.all_infer += 1; variant.all_infer += 1 }
                 }
-                println!("Ty interner             total           ty region  both");
+                println!("Ty interner             total           ty lt ct all");
                 $(println!("    {:18}: {uses:6} {usespc:4.1}%, \
-                            {ty:4.1}% {region:5.1}% {both:4.1}%",
-                           stringify!($variant),
-                           uses = $variant.total,
-                           usespc = $variant.total as f64 * 100.0 / total.total as f64,
-                           ty = $variant.ty_infer as f64 * 100.0  / total.total as f64,
-                           region = $variant.region_infer as f64 * 100.0  / total.total as f64,
-                           both = $variant.both_infer as f64 * 100.0  / total.total as f64);
-                  )*
+                            {ty:4.1}% {lt:5.1}% {ct:4.1}% {all:4.1}%",
+                    stringify!($variant),
+                    uses = $variant.total,
+                    usespc = $variant.total as f64 * 100.0 / total.total as f64,
+                    ty = $variant.ty_infer as f64 * 100.0  / total.total as f64,
+                    lt = $variant.lt_infer as f64 * 100.0  / total.total as f64,
+                    ct = $variant.ct_infer as f64 * 100.0  / total.total as f64,
+                    all = $variant.all_infer as f64 * 100.0  / total.total as f64);
+                )*
                 println!("                  total {uses:6}        \
-                          {ty:4.1}% {region:5.1}% {both:4.1}%",
-                         uses = total.total,
-                         ty = total.ty_infer as f64 * 100.0  / total.total as f64,
-                         region = total.region_infer as f64 * 100.0  / total.total as f64,
-                         both = total.both_infer as f64 * 100.0  / total.total as f64)
+                          {ty:4.1}% {lt:5.1}% {ct:4.1}% {all:4.1}%",
+                    uses = total.total,
+                    ty = total.ty_infer as f64 * 100.0  / total.total as f64,
+                    lt = total.lt_infer as f64 * 100.0  / total.total as f64,
+                    ct = total.ct_infer as f64 * 100.0  / total.total as f64,
+                    all = total.all_infer as f64 * 100.0  / total.total as f64)
             }
         }
 
@@ -2518,7 +2539,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         let adt_def = self.adt_def(def_id);
         let substs = InternalSubsts::for_item(self, def_id, |param, substs| {
             match param.kind {
-                GenericParamDefKind::Lifetime => bug!(),
+                GenericParamDefKind::Lifetime |
+                GenericParamDefKind::Const => {
+                    bug!()
+                }
                 GenericParamDefKind::Type { has_default, .. } => {
                     if param.index == 0 {
                         ty.into()
@@ -2659,11 +2683,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 
     #[inline]
-    pub fn mk_var(self, v: TyVid) -> Ty<'tcx> {
+    pub fn mk_ty_var(self, v: TyVid) -> Ty<'tcx> {
         self.mk_infer(TyVar(v))
     }
 
     #[inline]
+    pub fn mk_const_var(self, v: ConstVid<'tcx>, ty: Ty<'tcx>) -> &'tcx LazyConst<'tcx> {
+        self.mk_lazy_const(LazyConst::Evaluated(ty::Const {
+            val: ConstValue::Infer(InferConst::Var(v)),
+            ty,
+        }))
+    }
+
+    #[inline]
     pub fn mk_int_var(self, v: IntVid) -> Ty<'tcx> {
         self.mk_infer(IntVar(v))
     }
@@ -2686,6 +2718,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 
     #[inline]
+    pub fn mk_const_param(
+        self,
+        index: u32,
+        name: InternedString,
+        ty: Ty<'tcx>
+    ) -> &'tcx LazyConst<'tcx> {
+        self.mk_lazy_const(LazyConst::Evaluated(ty::Const {
+            val: ConstValue::Param(ParamConst { index, name }),
+            ty,
+        }))
+    }
+
+    #[inline]
     pub fn mk_self_type(self) -> Ty<'tcx> {
         self.mk_ty_param(0, keywords::SelfUpper.name().as_interned_str())
     }
@@ -2695,7 +2740,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             GenericParamDefKind::Lifetime => {
                 self.mk_region(ty::ReEarlyBound(param.to_early_bound_region_data())).into()
             }
-            GenericParamDefKind::Type {..} => self.mk_ty_param(param.index, param.name).into(),
+            GenericParamDefKind::Type { .. } => self.mk_ty_param(param.index, param.name).into(),
+            GenericParamDefKind::Const => {
+                self.mk_const_param(param.index, param.name, self.type_of(param.def_id)).into()
+            }
         }
     }
 
diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs
index 2b12dcca93a..64ceb9729ed 100644
--- a/src/librustc/ty/flags.rs
+++ b/src/librustc/ty/flags.rs
@@ -1,5 +1,6 @@
-use crate::ty::subst::SubstsRef;
-use crate::ty::{self, Ty, TypeFlags, TypeFoldable};
+use crate::ty::subst::{SubstsRef, UnpackedKind};
+use crate::ty::{self, Ty, TypeFlags, TypeFoldable, InferConst};
+use crate::mir::interpret::ConstValue;
 
 #[derive(Debug)]
 pub struct FlagComputation {
@@ -232,6 +233,21 @@ impl FlagComputation {
         }
     }
 
+    fn add_const(&mut self, c: &ty::LazyConst<'_>) {
+        match c {
+            ty::LazyConst::Unevaluated(_, substs) => self.add_substs(substs),
+            // Only done to add the binder for the type. The type flags are
+            // included in `Const::type_flags`.
+            ty::LazyConst::Evaluated(ty::Const { ty, val }) => {
+                self.add_ty(ty);
+                if let ConstValue::Infer(InferConst::Canonical(debruijn, _)) = val {
+                    self.add_binder(*debruijn)
+                }
+            }
+        }
+        self.add_flags(c.type_flags());
+    }
+
     fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) {
         self.add_substs(projection.substs);
         self.add_ty(projection.ty);
@@ -242,12 +258,12 @@ impl FlagComputation {
     }
 
     fn add_substs(&mut self, substs: SubstsRef<'_>) {
-        for ty in substs.types() {
-            self.add_ty(ty);
-        }
-
-        for r in substs.regions() {
-            self.add_region(r);
+        for kind in substs {
+            match kind.unpack() {
+                UnpackedKind::Type(ty) => self.add_ty(ty),
+                UnpackedKind::Lifetime(lt) => self.add_region(lt),
+                UnpackedKind::Const(ct) => self.add_const(ct),
+            }
         }
     }
 }
diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs
index aa4d1e5ea90..7f77d037bb6 100644
--- a/src/librustc/ty/fold.rs
+++ b/src/librustc/ty/fold.rs
@@ -91,7 +91,9 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
         self.has_type_flags(TypeFlags::HAS_TY_INFER)
     }
     fn needs_infer(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_RE_INFER)
+        self.has_type_flags(
+            TypeFlags::HAS_TY_INFER | TypeFlags::HAS_RE_INFER | TypeFlags::HAS_CT_INFER
+        )
     }
     fn has_placeholders(&self) -> bool {
         self.has_type_flags(TypeFlags::HAS_RE_PLACEHOLDER | TypeFlags::HAS_TY_PLACEHOLDER)
@@ -117,7 +119,7 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
     }
 
     /// Indicates whether this value references only 'global'
-    /// types/lifetimes that are the same regardless of what fn we are
+    /// generic parameters that are the same regardless of what fn we are
     /// in. This is used for caching.
     fn is_global(&self) -> bool {
         !self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES)
@@ -841,14 +843,13 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
     }
 
     fn visit_const(&mut self, c: &'tcx ty::LazyConst<'tcx>) -> bool {
-        if let ty::LazyConst::Unevaluated(..) = c {
-            let projection_flags = TypeFlags::HAS_NORMALIZABLE_PROJECTION |
-                TypeFlags::HAS_PROJECTION;
-            if projection_flags.intersects(self.flags) {
-                return true;
-            }
+        let flags = c.type_flags();
+        debug!("HasTypeFlagsVisitor: c={:?} c.flags={:?} self.flags={:?}", c, flags, self.flags);
+        if flags.intersects(self.flags) {
+            true
+        } else {
+            c.super_visit_with(self)
         }
-        c.super_visit_with(self)
     }
 }
 
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 1f897d29a1e..a649e312b43 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -54,14 +54,14 @@ use crate::hir;
 
 pub use self::sty::{Binder, BoundTy, BoundTyKind, BoundVar, DebruijnIndex, INNERMOST};
 pub use self::sty::{FnSig, GenSig, CanonicalPolyFnSig, PolyFnSig, PolyGenSig};
-pub use self::sty::{InferTy, ParamTy, ProjectionTy, ExistentialPredicate};
+pub use self::sty::{InferTy, ParamTy, ParamConst, InferConst, ProjectionTy, ExistentialPredicate};
 pub use self::sty::{ClosureSubsts, GeneratorSubsts, UpvarSubsts, TypeAndMut};
 pub use self::sty::{TraitRef, TyKind, PolyTraitRef};
 pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef};
 pub use self::sty::{ExistentialProjection, PolyExistentialProjection, Const, LazyConst};
 pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region};
 pub use self::sty::RegionKind;
-pub use self::sty::{TyVid, IntVid, FloatVid, RegionVid};
+pub use self::sty::{TyVid, IntVid, FloatVid, ConstVid, RegionVid};
 pub use self::sty::BoundRegion::*;
 pub use self::sty::InferTy::*;
 pub use self::sty::RegionKind::*;
@@ -451,6 +451,8 @@ bitflags! {
 
         const HAS_TY_PLACEHOLDER = 1 << 14;
 
+        const HAS_CT_INFER = 1 << 15;
+
         const NEEDS_SUBST        = TypeFlags::HAS_PARAMS.bits |
                                    TypeFlags::HAS_SELF.bits |
                                    TypeFlags::HAS_RE_EARLY_BOUND.bits;
@@ -462,6 +464,7 @@ bitflags! {
                                   TypeFlags::HAS_SELF.bits |
                                   TypeFlags::HAS_TY_INFER.bits |
                                   TypeFlags::HAS_RE_INFER.bits |
+                                  TypeFlags::HAS_CT_INFER.bits |
                                   TypeFlags::HAS_RE_PLACEHOLDER.bits |
                                   TypeFlags::HAS_RE_EARLY_BOUND.bits |
                                   TypeFlags::HAS_FREE_REGIONS.bits |
@@ -837,7 +840,8 @@ pub enum GenericParamDefKind {
         has_default: bool,
         object_lifetime_default: ObjectLifetimeDefault,
         synthetic: Option<hir::SyntheticTyParamKind>,
-    }
+    },
+    Const,
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable)]
@@ -880,6 +884,7 @@ impl GenericParamDef {
 pub struct GenericParamCount {
     pub lifetimes: usize,
     pub types: usize,
+    pub consts: usize,
 }
 
 /// Information about the formal type/lifetime parameters associated
@@ -915,6 +920,7 @@ impl<'a, 'gcx, 'tcx> Generics {
             match param.kind {
                 GenericParamDefKind::Lifetime => own_counts.lifetimes += 1,
                 GenericParamDefKind::Type { .. } => own_counts.types += 1,
+                GenericParamDefKind::Const => own_counts.consts += 1,
             };
         }
 
@@ -924,7 +930,7 @@ impl<'a, 'gcx, 'tcx> Generics {
     pub fn requires_monomorphization(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool {
         for param in &self.params {
             match param.kind {
-                GenericParamDefKind::Type { .. } => return true,
+                GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => return true,
                 GenericParamDefKind::Lifetime => {}
             }
         }
@@ -944,7 +950,7 @@ impl<'a, 'gcx, 'tcx> Generics {
         if let Some(index) = param.index.checked_sub(self.parent_count as u32) {
             let param = &self.params[index as usize];
             match param.kind {
-                ty::GenericParamDefKind::Lifetime => param,
+                GenericParamDefKind::Lifetime => param,
                 _ => bug!("expected lifetime parameter, but found another generic parameter")
             }
         } else {
@@ -961,7 +967,7 @@ impl<'a, 'gcx, 'tcx> Generics {
         if let Some(index) = param.idx.checked_sub(self.parent_count as u32) {
             let param = &self.params[index as usize];
             match param.kind {
-                ty::GenericParamDefKind::Type {..} => param,
+                GenericParamDefKind::Type { .. } => param,
                 _ => bug!("expected type parameter, but found another generic parameter")
             }
         } else {
@@ -969,6 +975,23 @@ impl<'a, 'gcx, 'tcx> Generics {
                .type_param(param, tcx)
         }
     }
+
+    /// Returns the `ConstParameterDef` associated with this `ParamConst`.
+    pub fn const_param(&'tcx self,
+                       param: &ParamConst,
+                       tcx: TyCtxt<'a, 'gcx, 'tcx>)
+                       -> &GenericParamDef {
+        if let Some(index) = param.index.checked_sub(self.parent_count as u32) {
+            let param = &self.params[index as usize];
+            match param.kind {
+                GenericParamDefKind::Const => param,
+                _ => bug!("expected const parameter, but found another generic parameter")
+            }
+        } else {
+            tcx.generics_of(self.parent.expect("parent_count>0 but no parent?"))
+                .const_param(param, tcx)
+        }
+    }
 }
 
 /// Bounds on generics.
diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs
index 2940757fa90..3a31801b3be 100644
--- a/src/librustc/ty/relate.rs
+++ b/src/librustc/ty/relate.rs
@@ -705,6 +705,9 @@ impl<'tcx> Relate<'tcx> for Kind<'tcx> {
             (UnpackedKind::Type(unpacked), x) => {
                 bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x)
             }
+            (UnpackedKind::Const(_), _) => {
+                unimplemented!() // FIXME(const_generics)
+            }
         }
     }
 }
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index f1a465e1f17..f9eb336a4a3 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -5,12 +5,13 @@
 
 use crate::mir::ProjectionKind;
 use crate::mir::interpret::ConstValue;
-use crate::ty::{self, Lift, Ty, TyCtxt};
+use crate::ty::{self, Lift, Ty, TyCtxt, ConstVid, InferConst};
 use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 use rustc_data_structures::indexed_vec::{IndexVec, Idx};
 use smallvec::SmallVec;
 use crate::mir::interpret;
 
+use std::marker::PhantomData;
 use std::rc::Rc;
 
 ///////////////////////////////////////////////////////////////////////////
@@ -49,6 +50,7 @@ CloneTypeFoldableAndLiftImpls! {
     crate::ty::BoundRegion,
     crate::ty::ClosureKind,
     crate::ty::IntVarValue,
+    crate::ty::ParamConst,
     crate::ty::ParamTy,
     crate::ty::UniverseIndex,
     crate::ty::Variance,
@@ -503,6 +505,14 @@ impl<'a, 'tcx> Lift<'tcx> for ConstValue<'a> {
     type Lifted = ConstValue<'tcx>;
     fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
         match *self {
+            ConstValue::Param(param) => Some(ConstValue::Param(param)),
+            ConstValue::Infer(infer) => {
+                Some(ConstValue::Infer(match infer {
+                    InferConst::Var(vid) => InferConst::Var(vid.lift_to_tcx(tcx)?),
+                    InferConst::Fresh(i) => InferConst::Fresh(i),
+                    InferConst::Canonical(debrujin, var) => InferConst::Canonical(debrujin, var),
+                }))
+            }
             ConstValue::Scalar(x) => Some(ConstValue::Scalar(x)),
             ConstValue::Slice(x, y) => Some(ConstValue::Slice(x, y)),
             ConstValue::ByRef(ptr, alloc) => Some(ConstValue::ByRef(
@@ -512,6 +522,16 @@ impl<'a, 'tcx> Lift<'tcx> for ConstValue<'a> {
     }
 }
 
+impl<'a, 'tcx> Lift<'tcx> for ConstVid<'a> {
+    type Lifted = ConstVid<'tcx>;
+    fn lift_to_tcx<'b, 'gcx>(&self, _: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
+        Some(ConstVid {
+            index: self.index,
+            phantom: PhantomData,
+        })
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // TypeFoldable implementations.
 //
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 3fd2e38a3d3..1aa4ca7ff97 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -16,6 +16,7 @@ use crate::mir::interpret::{Scalar, Pointer};
 use smallvec::SmallVec;
 use std::iter;
 use std::cmp::Ordering;
+use std::marker::PhantomData;
 use rustc_target::spec::abi;
 use syntax::ast::{self, Ident};
 use syntax::symbol::{keywords, InternedString};
@@ -1061,6 +1062,26 @@ impl<'a, 'gcx, 'tcx> ParamTy {
     }
 }
 
+#[derive(Copy, Clone, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq, Ord, PartialOrd)]
+pub struct ParamConst {
+    pub index: u32,
+    pub name: InternedString,
+}
+
+impl<'a, 'gcx, 'tcx> ParamConst {
+    pub fn new(index: u32, name: InternedString) -> ParamConst {
+        ParamConst { index, name }
+    }
+
+    pub fn for_def(def: &ty::GenericParamDef) -> ParamConst {
+        ParamConst::new(def.index, def.name)
+    }
+
+    pub fn to_const(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, ty: Ty<'tcx>) -> &'tcx LazyConst<'tcx> {
+        tcx.mk_const_param(self.index, self.name, ty)
+    }
+}
+
 /// A [De Bruijn index][dbi] is a standard means of representing
 /// regions (and perhaps later types) in a higher-ranked setting. In
 /// particular, imagine a type like this:
@@ -1230,6 +1251,12 @@ pub struct TyVid {
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
+pub struct ConstVid<'tcx> {
+    pub index: u32,
+    pub phantom: PhantomData<&'tcx ()>,
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
 pub struct IntVid {
     pub index: u32,
 }
@@ -2083,6 +2110,22 @@ impl<'tcx> LazyConst<'tcx> {
     pub fn unwrap_usize(&self, tcx: TyCtxt<'_, '_, '_>) -> u64 {
         self.assert_usize(tcx).expect("expected `LazyConst` to contain a usize")
     }
+
+    pub fn type_flags(&self) -> TypeFlags {
+        // FIXME(const_generics): incorporate substs flags.
+        let flags = match self {
+            LazyConst::Unevaluated(..) => {
+                TypeFlags::HAS_NORMALIZABLE_PROJECTION | TypeFlags::HAS_PROJECTION
+            }
+            LazyConst::Evaluated(c) => {
+                c.type_flags()
+            }
+        };
+
+        debug!("type_flags({:?}) = {:?}", self, flags);
+
+        flags
+    }
 }
 
 /// Typed constant value.
@@ -2198,6 +2241,44 @@ impl<'tcx> Const<'tcx> {
         self.assert_usize(tcx).unwrap_or_else(||
             bug!("expected constant usize, got {:#?}", self))
     }
+
+    pub fn type_flags(&self) -> TypeFlags {
+        let mut flags = self.ty.flags;
+
+        match self.val {
+            ConstValue::Param(_) => {
+                flags |= TypeFlags::HAS_FREE_LOCAL_NAMES;
+                flags |= TypeFlags::HAS_PARAMS;
+            }
+            ConstValue::Infer(infer) => {
+                flags |= TypeFlags::HAS_FREE_LOCAL_NAMES;
+                flags |= TypeFlags::HAS_CT_INFER;
+                match infer {
+                    InferConst::Fresh(_) |
+                    InferConst::Canonical(_, _) => {}
+                    InferConst::Var(_) => {
+                        flags |= TypeFlags::KEEP_IN_LOCAL_TCX;
+                    }
+                }
+            }
+            _ => {}
+        }
+
+        debug!("type_flags({:?}) = {:?}", self, flags);
+
+        flags
+    }
 }
 
 impl<'tcx> serialize::UseSpecializedDecodable for &'tcx LazyConst<'tcx> {}
+
+/// An inference variable for a const, for use in const generics.
+#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)]
+pub enum InferConst<'tcx> {
+    /// Infer the value of the const.
+    Var(ConstVid<'tcx>),
+    /// A fresh const variable. See `infer::freshen` for more details.
+    Fresh(u32),
+    /// Canonicalized const variable, used only when preparing a trait query.
+    Canonical(DebruijnIndex, BoundVar),
+}
diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs
index 450fab81661..35c6f980cd9 100644
--- a/src/librustc/ty/subst.rs
+++ b/src/librustc/ty/subst.rs
@@ -2,8 +2,9 @@
 
 use crate::hir::def_id::DefId;
 use crate::infer::canonical::Canonical;
-use crate::ty::{self, Lift, List, Ty, TyCtxt};
+use crate::ty::{self, Lift, List, Ty, TyCtxt, InferConst, ParamConst};
 use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
+use crate::mir::interpret::ConstValue;
 
 use serialize::{self, Encodable, Encoder, Decodable, Decoder};
 use syntax_pos::{Span, DUMMY_SP};
@@ -17,24 +18,26 @@ use std::mem;
 use std::num::NonZeroUsize;
 
 /// An entity in the Rust type system, which can be one of
-/// several kinds (only types and lifetimes for now).
+/// several kinds (types, lifetimes, and consts).
 /// To reduce memory usage, a `Kind` is a interned pointer,
 /// with the lowest 2 bits being reserved for a tag to
-/// indicate the type (`Ty` or `Region`) it points to.
+/// indicate the type (`Ty`, `Region`, or `Const`) it points to.
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Kind<'tcx> {
     ptr: NonZeroUsize,
-    marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>)>
+    marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>, &'tcx ty::LazyConst<'tcx>)>
 }
 
 const TAG_MASK: usize = 0b11;
 const TYPE_TAG: usize = 0b00;
 const REGION_TAG: usize = 0b01;
+const CONST_TAG: usize = 0b10;
 
 #[derive(Debug, RustcEncodable, RustcDecodable, PartialEq, Eq, PartialOrd, Ord)]
 pub enum UnpackedKind<'tcx> {
     Lifetime(ty::Region<'tcx>),
     Type(Ty<'tcx>),
+    Const(&'tcx ty::LazyConst<'tcx>),
 }
 
 impl<'tcx> UnpackedKind<'tcx> {
@@ -50,6 +53,11 @@ impl<'tcx> UnpackedKind<'tcx> {
                 assert_eq!(mem::align_of_val(ty) & TAG_MASK, 0);
                 (TYPE_TAG, ty as *const _ as usize)
             }
+            UnpackedKind::Const(ct) => {
+                // Ensure we can use the tag bits.
+                assert_eq!(mem::align_of_val(ct) & TAG_MASK, 0);
+                (CONST_TAG, ct as *const _ as usize)
+            }
         };
 
         Kind {
@@ -85,6 +93,12 @@ impl<'tcx> From<Ty<'tcx>> for Kind<'tcx> {
     }
 }
 
+impl<'tcx> From<&'tcx ty::LazyConst<'tcx>> for Kind<'tcx> {
+    fn from(c: &'tcx ty::LazyConst<'tcx>) -> Kind<'tcx> {
+        UnpackedKind::Const(c).pack()
+    }
+}
+
 impl<'tcx> Kind<'tcx> {
     #[inline]
     pub fn unpack(self) -> UnpackedKind<'tcx> {
@@ -93,6 +107,7 @@ impl<'tcx> Kind<'tcx> {
             match ptr & TAG_MASK {
                 REGION_TAG => UnpackedKind::Lifetime(&*((ptr & !TAG_MASK) as *const _)),
                 TYPE_TAG => UnpackedKind::Type(&*((ptr & !TAG_MASK) as *const _)),
+                CONST_TAG => UnpackedKind::Const(&*((ptr & !TAG_MASK) as *const _)),
                 _ => intrinsics::unreachable()
             }
         }
@@ -104,6 +119,7 @@ impl<'tcx> fmt::Debug for Kind<'tcx> {
         match self.unpack() {
             UnpackedKind::Lifetime(lt) => write!(f, "{:?}", lt),
             UnpackedKind::Type(ty) => write!(f, "{:?}", ty),
+            UnpackedKind::Const(ct) => write!(f, "{:?}", ct),
         }
     }
 }
@@ -113,6 +129,7 @@ impl<'tcx> fmt::Display for Kind<'tcx> {
         match self.unpack() {
             UnpackedKind::Lifetime(lt) => write!(f, "{}", lt),
             UnpackedKind::Type(ty) => write!(f, "{}", ty),
+            UnpackedKind::Const(ct) => write!(f, "{}", ct),
         }
     }
 }
@@ -122,8 +139,9 @@ impl<'a, 'tcx> Lift<'tcx> for Kind<'a> {
 
     fn lift_to_tcx<'cx, 'gcx>(&self, tcx: TyCtxt<'cx, 'gcx, 'tcx>) -> Option<Self::Lifted> {
         match self.unpack() {
-            UnpackedKind::Lifetime(a) => a.lift_to_tcx(tcx).map(|a| a.into()),
-            UnpackedKind::Type(a) => a.lift_to_tcx(tcx).map(|a| a.into()),
+            UnpackedKind::Lifetime(lt) => lt.lift_to_tcx(tcx).map(|lt| lt.into()),
+            UnpackedKind::Type(ty) => ty.lift_to_tcx(tcx).map(|ty| ty.into()),
+            UnpackedKind::Const(ct) => ct.lift_to_tcx(tcx).map(|ct| ct.into()),
         }
     }
 }
@@ -133,6 +151,7 @@ impl<'tcx> TypeFoldable<'tcx> for Kind<'tcx> {
         match self.unpack() {
             UnpackedKind::Lifetime(lt) => lt.fold_with(folder).into(),
             UnpackedKind::Type(ty) => ty.fold_with(folder).into(),
+            UnpackedKind::Const(ct) => ct.fold_with(folder).into(),
         }
     }
 
@@ -140,6 +159,7 @@ impl<'tcx> TypeFoldable<'tcx> for Kind<'tcx> {
         match self.unpack() {
             UnpackedKind::Lifetime(lt) => lt.visit_with(visitor),
             UnpackedKind::Type(ty) => ty.visit_with(visitor),
+            UnpackedKind::Const(ct) => ct.visit_with(visitor),
         }
     }
 }
@@ -195,6 +215,15 @@ impl<'a, 'gcx, 'tcx> InternalSubsts<'tcx> {
                         ty::BoundRegion::BrNamed(param.def_id, param.name)
                     )).into()
                 }
+
+                ty::GenericParamDefKind::Const => {
+                    tcx.mk_lazy_const(ty::LazyConst::Evaluated(ty::Const {
+                        val: ConstValue::Infer(
+                            InferConst::Canonical(ty::INNERMOST, ty::BoundVar::from(param.index))
+                        ),
+                        ty: tcx.type_of(def_id),
+                    })).into()
+                }
             }
         })
     }
@@ -284,6 +313,29 @@ impl<'a, 'gcx, 'tcx> InternalSubsts<'tcx> {
     }
 
     #[inline]
+    pub fn consts(&'a self) -> impl DoubleEndedIterator<Item = &'tcx ty::LazyConst<'tcx>> + 'a {
+        self.iter().filter_map(|k| {
+            if let UnpackedKind::Const(ct) = k.unpack() {
+                Some(ct)
+            } else {
+                None
+            }
+        })
+    }
+
+    #[inline]
+    pub fn non_erasable_generics(
+        &'a self
+    ) -> impl DoubleEndedIterator<Item = UnpackedKind<'tcx>> + 'a {
+        self.iter().filter_map(|k| {
+            match k.unpack() {
+                UnpackedKind::Lifetime(_) => None,
+                generic => Some(generic),
+            }
+        })
+    }
+
+    #[inline]
     pub fn type_at(&self, i: usize) -> Ty<'tcx> {
         if let UnpackedKind::Type(ty) = self[i].unpack() {
             ty
@@ -302,6 +354,15 @@ impl<'a, 'gcx, 'tcx> InternalSubsts<'tcx> {
     }
 
     #[inline]
+    pub fn const_at(&self, i: usize) -> &'tcx ty::LazyConst<'tcx> {
+        if let UnpackedKind::Const(ct) = self[i].unpack() {
+            ct
+        } else {
+            bug!("expected const for param #{} in {:?}", i, self);
+        }
+    }
+
+    #[inline]
     pub fn type_for_def(&self, def: &ty::GenericParamDef) -> Kind<'tcx> {
         self.type_at(def.index as usize).into()
     }
@@ -469,6 +530,21 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> {
 
         return t1;
     }
+
+    fn fold_const(&mut self, c: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> {
+        if !c.needs_subst() {
+            return c;
+        }
+
+        if let ty::LazyConst::Evaluated(ty::Const {
+            val: ConstValue::Param(p),
+            ..
+        }) = c {
+            self.const_for_param(*p, c)
+        } else {
+            c.super_fold_with(self)
+        }
+    }
 }
 
 impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> {
@@ -494,6 +570,34 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> {
         self.shift_vars_through_binders(ty)
     }
 
+    fn const_for_param(
+        &self,
+        p: ParamConst,
+        source_cn: &'tcx ty::LazyConst<'tcx>
+    ) -> &'tcx ty::LazyConst<'tcx> {
+        // Look up the const in the substitutions. It really should be in there.
+        let opt_cn = self.substs.get(p.index as usize).map(|k| k.unpack());
+        let cn = match opt_cn {
+            Some(UnpackedKind::Const(cn)) => cn,
+            _ => {
+                let span = self.span.unwrap_or(DUMMY_SP);
+                span_bug!(
+                    span,
+                    "Const parameter `{:?}` ({:?}/{}) out of range \
+                     when substituting (root type={:?}) substs={:?}",
+                    p,
+                    source_cn,
+                    p.index,
+                    self.root_ty,
+                    self.substs,
+                );
+            }
+        };
+
+        // FIXME(const_generics): shift const through binders
+        cn
+    }
+
     /// It is sometimes necessary to adjust the De Bruijn indices during substitution. This occurs
     /// when we are substituting a type with escaping bound vars into a context where we have
     /// passed through binders. That's quite a mouthful. Let's see an example:
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 4ad3ffaa93d..fb0d1e2080b 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -12,6 +12,7 @@ use crate::ty::subst::{Subst, InternalSubsts, SubstsRef, UnpackedKind};
 use crate::ty::query::TyCtxtAt;
 use crate::ty::TyKind::*;
 use crate::ty::layout::{Integer, IntegerExt};
+use crate::mir::interpret::ConstValue;
 use crate::util::common::ErrorReported;
 use crate::middle::lang_items;
 
@@ -495,8 +496,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                     }) => {
                         !impl_generics.type_param(pt, self).pure_wrt_drop
                     }
-                    UnpackedKind::Lifetime(_) | UnpackedKind::Type(_) => {
-                        // not a type or region param - this should be reported
+                    UnpackedKind::Const(&ty::LazyConst::Evaluated(ty::Const {
+                        val: ConstValue::Param(ref pc),
+                        ..
+                    })) => {
+                        !impl_generics.const_param(pc, self).pure_wrt_drop
+                    }
+                    UnpackedKind::Lifetime(_) |
+                    UnpackedKind::Type(_) |
+                    UnpackedKind::Const(_) => {
+                        // Not a type, const or region param: this should be reported
                         // as an error.
                         false
                     }
@@ -587,15 +596,18 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         Some(ty::Binder::bind(env_ty))
     }
 
-    /// Given the `DefId` of some item that has no type parameters, make
+    /// Given the `DefId` of some item that has no type or const parameters, make
     /// a suitable "empty substs" for it.
     pub fn empty_substs_for_def_id(self, item_def_id: DefId) -> SubstsRef<'tcx> {
         InternalSubsts::for_item(self, item_def_id, |param, _| {
             match param.kind {
                 GenericParamDefKind::Lifetime => self.types.re_erased.into(),
-                GenericParamDefKind::Type {..} => {
+                GenericParamDefKind::Type { .. } => {
                     bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id)
                 }
+                GenericParamDefKind::Const { .. } => {
+                    bug!("empty_substs_for_def_id: {:?} has const parameters", item_def_id)
+                }
             }
         })
     }
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index aecef3c5ec7..cdc0c3371eb 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -8,7 +8,8 @@ use crate::ty::{Error, Str, Array, Slice, Float, FnDef, FnPtr};
 use crate::ty::{Param, Bound, RawPtr, Ref, Never, Tuple};
 use crate::ty::{Closure, Generator, GeneratorWitness, Foreign, Projection, Opaque};
 use crate::ty::{Placeholder, UnnormalizedProjection, Dynamic, Int, Uint, Infer};
-use crate::ty::{self, Ty, TyCtxt, TypeFoldable, GenericParamCount, GenericParamDefKind};
+use crate::ty::{self, Ty, TyCtxt, TypeFoldable, GenericParamCount, GenericParamDefKind, ParamConst};
+use crate::mir::interpret::ConstValue;
 use crate::util::nodemap::FxHashSet;
 
 use std::cell::Cell;
@@ -478,6 +479,7 @@ impl PrintContext {
                         GenericParamDefKind::Type { has_default, .. } => {
                             Some((param.def_id, has_default))
                         }
+                        GenericParamDefKind::Const => None, // FIXME(const_generics:defaults)
                     }).peekable();
                 let has_default = {
                     let has_default = type_params.peek().map(|(_, has_default)| has_default);
@@ -571,6 +573,14 @@ impl PrintContext {
             )?;
         }
 
+        // FIXME(const_generics::defaults)
+        let consts = substs.consts();
+
+        for ct in consts {
+            start_or_continue(f, "<", ", ")?;
+            ct.print_display(f, self)?;
+        }
+
         start_or_continue(f, "", ">")?;
 
         // For values, also print their name and type parameters.
@@ -763,7 +773,8 @@ impl fmt::Debug for ty::GenericParamDef {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let type_name = match self.kind {
             ty::GenericParamDefKind::Lifetime => "Lifetime",
-            ty::GenericParamDefKind::Type {..} => "Type",
+            ty::GenericParamDefKind::Type { .. } => "Type",
+            ty::GenericParamDefKind::Const => "Const",
         };
         write!(f, "{}({}, {:?}, {})",
                type_name,
@@ -1088,6 +1099,12 @@ impl fmt::Debug for ty::TyVid {
     }
 }
 
+impl<'tcx> fmt::Debug for ty::ConstVid<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "_#{}f", self.index)
+    }
+}
+
 impl fmt::Debug for ty::IntVid {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "_#{}i", self.index)
@@ -1448,7 +1465,12 @@ define_print! {
                             write!(f, "_")?;
                         }
                         ty::LazyConst::Evaluated(c) => ty::tls::with(|tcx| {
-                            write!(f, "{}", c.unwrap_usize(tcx))
+                            match c.val {
+                                ConstValue::Infer(..) => write!(f, "_"),
+                                ConstValue::Param(ParamConst { name, .. }) =>
+                                    write!(f, "{}", name),
+                                _ => write!(f, "{}", c.unwrap_usize(tcx)),
+                            }
                         })?,
                     }
                     write!(f, "]")
@@ -1473,6 +1495,37 @@ define_print! {
 }
 
 define_print! {
+    ('tcx) ConstValue<'tcx>, (self, f, cx) {
+        display {
+            match self {
+                ConstValue::Infer(..) => write!(f, "_"),
+                ConstValue::Param(ParamConst { name, .. }) => write!(f, "{}", name),
+                _ => write!(f, "{:?}", self),
+            }
+        }
+    }
+}
+
+define_print! {
+    ('tcx) ty::Const<'tcx>, (self, f, cx) {
+        display {
+            write!(f, "{} : {}", self.val, self.ty)
+        }
+    }
+}
+
+define_print! {
+    ('tcx) ty::LazyConst<'tcx>, (self, f, cx) {
+        display {
+            match self {
+                ty::LazyConst::Unevaluated(..) => write!(f, "_ : _"),
+                ty::LazyConst::Evaluated(c) => write!(f, "{}", c),
+            }
+        }
+    }
+}
+
+define_print! {
     () ty::ParamTy, (self, f, cx) {
         display {
             write!(f, "{}", self.name)
@@ -1484,6 +1537,17 @@ define_print! {
 }
 
 define_print! {
+    () ty::ParamConst, (self, f, cx) {
+        display {
+            write!(f, "{}", self.name)
+        }
+        debug {
+            write!(f, "{}/#{}", self.name, self.index)
+        }
+    }
+}
+
+define_print! {
     ('tcx, T: Print + fmt::Debug, U: Print + fmt::Debug) ty::OutlivesPredicate<T, U>,
     (self, f, cx) {
         display {
diff --git a/src/librustc_codegen_llvm/callee.rs b/src/librustc_codegen_llvm/callee.rs
index 43a5767e5c6..2d732adcb91 100644
--- a/src/librustc_codegen_llvm/callee.rs
+++ b/src/librustc_codegen_llvm/callee.rs
@@ -113,7 +113,7 @@ pub fn get_fn(
         unsafe {
             llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage);
 
-            let is_generic = instance.substs.types().next().is_some();
+            let is_generic = instance.substs.non_erasable_generics().next().is_some();
 
             if is_generic {
                 // This is a monomorphization. Its expected visibility depends
diff --git a/src/librustc_codegen_ssa/back/symbol_export.rs b/src/librustc_codegen_ssa/back/symbol_export.rs
index 7da28c19d24..336f41b784a 100644
--- a/src/librustc_codegen_ssa/back/symbol_export.rs
+++ b/src/librustc_codegen_ssa/back/symbol_export.rs
@@ -263,7 +263,7 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 def: InstanceDef::Item(def_id),
                 substs,
             }) = mono_item {
-                if substs.types().next().is_some() {
+                if substs.non_erasable_generics().next().is_some() {
                     symbols.push((ExportedSymbol::Generic(def_id, substs),
                                   SymbolExportLevel::Rust));
                 }
diff --git a/src/librustc_codegen_ssa/mir/operand.rs b/src/librustc_codegen_ssa/mir/operand.rs
index 0a6549851f4..55a1eb016e0 100644
--- a/src/librustc_codegen_ssa/mir/operand.rs
+++ b/src/librustc_codegen_ssa/mir/operand.rs
@@ -76,6 +76,8 @@ impl<'a, 'tcx: 'a, V: CodegenObject> OperandRef<'tcx, V> {
         }
 
         let val = match val.val {
+            ConstValue::Param(_) => bug!("encountered a ConstValue::Param in codegen"),
+            ConstValue::Infer(_) => bug!("encountered a ConstValue::Infer in codegen"),
             ConstValue::Scalar(x) => {
                 let scalar = match layout.abi {
                     layout::Abi::Scalar(ref x) => x,
diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs
index f529cf30a62..76e74e9e2b4 100644
--- a/src/librustc_codegen_utils/symbol_names.rs
+++ b/src/librustc_codegen_utils/symbol_names.rs
@@ -172,7 +172,7 @@ fn get_symbol_hash<'a, 'tcx>(
         assert!(!substs.needs_subst());
         substs.hash_stable(&mut hcx, &mut hasher);
 
-        let is_generic = substs.types().next().is_some();
+        let is_generic = substs.non_erasable_generics().next().is_some();
         let avoid_cross_crate_conflicts =
             // If this is an instance of a generic function, we also hash in
             // the ID of the instantiating crate. This avoids symbol conflicts
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs
index cc01f632e07..fdede054e15 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs
@@ -604,7 +604,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                     search_stack.push((ty, hir_ty));
                 }
 
-                (UnpackedKind::Lifetime(_), _) | (UnpackedKind::Type(_), _) => {
+                (UnpackedKind::Const(_ct), hir::GenericArg::Const(_hir_ct)) => {
+                    // Lifetimes cannot be found in consts, so we don't need
+                    // to search anything here.
+                }
+
+                (UnpackedKind::Lifetime(_), _)
+                | (UnpackedKind::Type(_), _)
+                | (UnpackedKind::Const(_), _) => {
                     // I *think* that HIR lowering should ensure this
                     // doesn't happen, even in erroneous
                     // programs. Else we should use delay-span-bug.
diff --git a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs
index 1a72205ad7a..bef159e996b 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs
@@ -99,6 +99,11 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
                     param_env,
                 ).type_must_outlive(origin, t1, r2);
             }
+
+            UnpackedKind::Const(_) => {
+                // Consts cannot outlive one another, so we
+                // don't need to handle any relations here.
+            }
         }
     }
 
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index cc03d4a0c96..5b444ab9690 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -2533,7 +2533,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                                     ),
                                 ))
                             }
-                            UnpackedKind::Type(_) => None,
+                            UnpackedKind::Type(_) | UnpackedKind::Const(_) => None,
                         }
                     })
                     .collect();
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 65cd9f7103d..e70756ad2f2 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -5,7 +5,7 @@ use crate::hair::cx::to_ref::ToRef;
 use crate::hair::util::UserAnnotatedTyHelpers;
 use rustc_data_structures::indexed_vec::Idx;
 use rustc::hir::def::{Def, CtorKind};
-use rustc::mir::interpret::{GlobalId, ErrorHandled};
+use rustc::mir::interpret::{GlobalId, ErrorHandled, ConstValue};
 use rustc::ty::{self, AdtKind, Ty};
 use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
 use rustc::ty::cast::CastKind as TyCastKind;
@@ -699,7 +699,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 };
 
                 let source = if let Some((did, offset, var_ty)) = var {
-                    let mk_const = |literal| Expr {
+                    let mk_lazy_const = |literal| Expr {
                         temp_lifetime,
                         ty: var_ty,
                         span: expr.span,
@@ -708,7 +708,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                             user_ty: None
                         },
                     }.to_ref();
-                    let offset = mk_const(ty::LazyConst::Evaluated(ty::Const::from_bits(
+                    let offset = mk_lazy_const(ty::LazyConst::Evaluated(ty::Const::from_bits(
                         cx.tcx,
                         offset as u128,
                         cx.param_env.and(var_ty),
@@ -718,7 +718,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                             // in case we are offsetting from a computed discriminant
                             // and not the beginning of discriminants (which is always `0`)
                             let substs = InternalSubsts::identity_for_item(cx.tcx(), did);
-                            let lhs = mk_const(ty::LazyConst::Unevaluated(did, substs));
+                            let lhs = mk_lazy_const(ty::LazyConst::Unevaluated(did, substs));
                             let bin = ExprKind::Binary {
                                 op: BinOp::Add,
                                 lhs,
@@ -925,7 +925,26 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 ))),
                 user_ty,
             }
-        },
+        }
+
+        Def::ConstParam(def_id) => {
+            let node_id = cx.tcx.hir().as_local_node_id(def_id).unwrap();
+            let item_id = cx.tcx.hir().get_parent_node(node_id);
+            let item_def_id = cx.tcx.hir().local_def_id(item_id);
+            let generics = cx.tcx.generics_of(item_def_id);
+            let index = generics.param_def_id_to_index[&cx.tcx.hir().local_def_id(node_id)];
+            let name = cx.tcx.hir().name(node_id).as_interned_str();
+            let val = ConstValue::Param(ty::ParamConst::new(index, name));
+            ExprKind::Literal {
+                literal: cx.tcx.mk_lazy_const(
+                    ty::LazyConst::Evaluated(ty::Const {
+                        val,
+                        ty: cx.tables().node_type(expr.hir_id),
+                    })
+                ),
+                user_ty: None,
+            }
+        }
 
         Def::Const(def_id) |
         Def::AssociatedConst(def_id) => {
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index 979595d6c00..206eaaf1787 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -589,11 +589,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
         val: ty::Const<'tcx>,
         layout: Option<TyLayout<'tcx>>,
     ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
+        let val = self.monomorphize(val)?;
         let layout = from_known_layout(layout, || {
-            let ty = self.monomorphize(val.ty)?;
-            self.layout_of(ty)
+            self.layout_of(val.ty)
         })?;
         let op = match val.val {
+            ConstValue::Param(_) | ConstValue::Infer(_) => bug!(),
             ConstValue::ByRef(ptr, alloc) => {
                 // We rely on mutability being set correctly in that allocation to prevent writes
                 // where none should happen -- and for `static mut`, we copy on demand anyway.
diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs
index 1f20c70dec5..4350bfcdc7a 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -466,7 +466,16 @@ fn check_type_length_limit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                      instance: Instance<'tcx>)
 {
     let type_length = instance.substs.types().flat_map(|ty| ty.walk()).count();
-    debug!(" => type length={}", type_length);
+    let const_length = instance.substs.consts()
+        .flat_map(|ct| {
+            let ty = match ct {
+                ty::LazyConst::Evaluated(ct) => ct.ty,
+                ty::LazyConst::Unevaluated(def_id, _) => tcx.type_of(*def_id),
+            };
+            ty.walk()
+        })
+        .count();
+    debug!(" => type length={}, const length={}", type_length, const_length);
 
     // Rust code can easily create exponentially-long types using only a
     // polynomial recursion depth. Even with the default recursion
@@ -475,7 +484,9 @@ fn check_type_length_limit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     //
     // Bail out in these cases to avoid that bad user experience.
     let type_length_limit = *tcx.sess.type_length_limit.get();
-    if type_length > type_length_limit {
+    // We include the const length in the type length, as it's better
+    // to be overly conservative.
+    if type_length + const_length > type_length_limit {
         // The instance name is already known to be too long for rustc. Use
         // `{:.64}` to avoid blasting the user's terminal with thousands of
         // lines of type-name.
@@ -490,7 +501,7 @@ fn check_type_length_limit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
         diag.note(&format!(
             "consider adding a `#![type_length_limit=\"{}\"]` attribute to your crate",
-            type_length_limit*2));
+            type_length_limit * 2));
         diag.emit();
         tcx.sess.abort_if_errors();
     }
@@ -759,10 +770,10 @@ fn should_monomorphize_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance:
             return false
         }
 
-        // If this instance has no type parameters, it cannot be a shared
+        // If this instance has non-erasable parameters, it cannot be a shared
         // monomorphization. Non-generic instances are already handled above
         // by `is_reachable_non_generic()`
-        if substs.types().next().is_none() {
+        if substs.non_erasable_generics().next().is_none() {
             return false
         }
 
@@ -1113,14 +1124,16 @@ fn create_mono_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                         continue;
                     }
 
-                    if tcx.generics_of(method.def_id).own_counts().types != 0 {
+                    let counts = tcx.generics_of(method.def_id).own_counts();
+                    if counts.types + counts.consts != 0 {
                         continue;
                     }
 
                     let substs = InternalSubsts::for_item(tcx, method.def_id, |param, _| {
                         match param.kind {
                             GenericParamDefKind::Lifetime => tcx.types.re_erased.into(),
-                            GenericParamDefKind::Type {..} => {
+                            GenericParamDefKind::Type { .. } |
+                            GenericParamDefKind::Const => {
                                 trait_ref.substs[param.index as usize]
                             }
                         }
diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs
index 059af2dbba9..f0d19ec8bf2 100644
--- a/src/librustc_mir/monomorphize/item.rs
+++ b/src/librustc_mir/monomorphize/item.rs
@@ -1,8 +1,9 @@
 use crate::monomorphize::Instance;
 use rustc::hir;
 use rustc::hir::def_id::{DefId, LOCAL_CRATE};
+use rustc::mir::interpret::ConstValue;
 use rustc::session::config::OptLevel;
-use rustc::ty::{self, Ty, TyCtxt, ClosureSubsts, GeneratorSubsts};
+use rustc::ty::{self, Ty, TyCtxt, Const, ClosureSubsts, GeneratorSubsts, LazyConst, ParamConst};
 use rustc::ty::subst::{SubstsRef, InternalSubsts};
 use syntax::ast;
 use syntax::attr::InlineAttr;
@@ -44,7 +45,7 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug {
     fn is_generic_fn(&self) -> bool {
         match *self.as_mono_item() {
             MonoItem::Fn(ref instance) => {
-                instance.substs.types().next().is_some()
+                instance.substs.non_erasable_generics().next().is_some()
             }
             MonoItem::Static(..) |
             MonoItem::GlobalAsm(..) => false,
@@ -267,7 +268,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
             ty::Float(ast::FloatTy::F64) => output.push_str("f64"),
             ty::Adt(adt_def, substs) => {
                 self.push_def_path(adt_def.did, output);
-                self.push_type_params(substs, iter::empty(), output, debug);
+                self.push_generic_params(substs, iter::empty(), output, debug);
             },
             ty::Tuple(component_types) => {
                 output.push('(');
@@ -312,7 +313,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
             ty::Dynamic(ref trait_data, ..) => {
                 if let Some(principal) = trait_data.principal() {
                     self.push_def_path(principal.def_id(), output);
-                    self.push_type_params(
+                    self.push_generic_params(
                         principal.skip_binder().substs,
                         trait_data.projection_bounds(),
                         output,
@@ -373,7 +374,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
                 self.push_def_path(def_id, output);
                 let generics = self.tcx.generics_of(self.tcx.closure_base_def_id(def_id));
                 let substs = substs.truncate_to(self.tcx, generics);
-                self.push_type_params(substs, iter::empty(), output, debug);
+                self.push_generic_params(substs, iter::empty(), output, debug);
             }
             ty::Error |
             ty::Bound(..) |
@@ -394,6 +395,24 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
         }
     }
 
+    // FIXME(const_generics): handle debug printing.
+    pub fn push_const_name(&self, c: &LazyConst<'tcx>, output: &mut String, debug: bool) {
+        match c {
+            LazyConst::Unevaluated(..) => output.push_str("_: _"),
+            LazyConst::Evaluated(Const { ty, val }) => {
+                match val {
+                    ConstValue::Infer(..) => output.push_str("_"),
+                    ConstValue::Param(ParamConst { name, .. }) => {
+                        write!(output, "{}", name).unwrap();
+                    }
+                    _ => write!(output, "{:?}", c).unwrap(),
+                }
+                output.push_str(": ");
+                self.push_type_name(ty, output, debug);
+            }
+        }
+    }
+
     pub fn push_def_path(&self,
                          def_id: DefId,
                          output: &mut String) {
@@ -421,15 +440,15 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
         output.pop();
     }
 
-    fn push_type_params<I>(&self,
-                            substs: SubstsRef<'tcx>,
-                            projections: I,
-                            output: &mut String,
-                            debug: bool)
-        where I: Iterator<Item=ty::PolyExistentialProjection<'tcx>>
-    {
+    fn push_generic_params<I>(
+        &self,
+        substs: SubstsRef<'tcx>,
+        projections: I,
+        output: &mut String,
+        debug: bool,
+    ) where I: Iterator<Item=ty::PolyExistentialProjection<'tcx>> {
         let mut projections = projections.peekable();
-        if substs.types().next().is_none() && projections.peek().is_none() {
+        if substs.non_erasable_generics().next().is_none() && projections.peek().is_none() {
             return;
         }
 
@@ -449,6 +468,11 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
             output.push_str(", ");
         }
 
+        for const_parameter in substs.consts() {
+            self.push_const_name(const_parameter, output, debug);
+            output.push_str(", ");
+        }
+
         output.pop();
         output.pop();
 
@@ -460,6 +484,6 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
                                    output: &mut String,
                                    debug: bool) {
         self.push_def_path(instance.def_id(), output);
-        self.push_type_params(instance.substs, iter::empty(), output, debug);
+        self.push_generic_params(instance.substs, iter::empty(), output, debug);
     }
 }
diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs
index f342017603e..f98bc476aaf 100644
--- a/src/librustc_mir/monomorphize/partitioning.rs
+++ b/src/librustc_mir/monomorphize/partitioning.rs
@@ -448,7 +448,7 @@ fn mono_item_visibility(
         return Visibility::Hidden
     }
 
-    let is_generic = instance.substs.types().next().is_some();
+    let is_generic = instance.substs.non_erasable_generics().next().is_some();
 
     // Upstream `DefId` instances get different handling than local ones
     if !def_id.is_local() {
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index db8476f3be5..1c6b1450be8 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -2,7 +2,7 @@ use rustc::hir;
 use rustc::hir::def_id::DefId;
 use rustc::infer;
 use rustc::mir::*;
-use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind};
+use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::layout::VariantIdx;
 use rustc::ty::subst::{Subst, InternalSubsts};
 use rustc::ty::query::Providers;
@@ -450,12 +450,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
     ) {
         let tcx = self.tcx;
 
-        let substs = InternalSubsts::for_item(tcx, self.def_id, |param, _| {
-            match param.kind {
-                GenericParamDefKind::Lifetime => tcx.types.re_erased.into(),
-                GenericParamDefKind::Type {..} => ty.into(),
-            }
-        });
+        let substs = tcx.mk_substs_trait(ty, &[]);
 
         // `func == Clone::clone(&ty) -> ty`
         let func_ty = tcx.mk_fn_def(self.def_id, substs);
diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs
index a8816720b28..047731e3fe6 100644
--- a/src/librustc_mir/transform/check_unsafety.rs
+++ b/src/librustc_mir/transform/check_unsafety.rs
@@ -558,9 +558,10 @@ fn unsafe_derive_on_repr_packed<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: D
 
     // FIXME: when we make this a hard error, this should have its
     // own error code.
-    let message = if tcx.generics_of(def_id).own_counts().types != 0 {
+    let counts = tcx.generics_of(def_id).own_counts();
+    let message = if counts.types + counts.consts != 0 {
         "#[derive] can't be used on a #[repr(packed)] struct with \
-         type parameters (error E0133)".to_string()
+         type or const parameters (error E0133)".to_string()
     } else {
         "#[derive] can't be used on a #[repr(packed)] struct that \
          does not derive Copy (error E0133)".to_string()
diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs
index 4cdef015b53..918375e426b 100644
--- a/src/librustc_mir/transform/inline.rs
+++ b/src/librustc_mir/transform/inline.rs
@@ -259,7 +259,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
         // inlining. This is to ensure that the final crate doesn't have MIR that
         // reference unexported symbols
         if callsite.callee.is_local() {
-            if callsite.substs.types().count() == 0 && !hinted {
+            if callsite.substs.non_erasable_generics().count() == 0 && !hinted {
                 debug!("    callee is an exported function - not inlining");
                 return false;
             }
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 550b333700b..a9f05eb60db 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -748,12 +748,15 @@ impl<'a, 'tcx> ReachEverythingInTheInterfaceVisitor<'_, 'a, 'tcx> {
     fn generics(&mut self) -> &mut Self {
         for param in &self.ev.tcx.generics_of(self.item_def_id).params {
             match param.kind {
+                GenericParamDefKind::Lifetime => {}
                 GenericParamDefKind::Type { has_default, .. } => {
                     if has_default {
                         self.visit(self.ev.tcx.type_of(param.def_id));
                     }
                 }
-                GenericParamDefKind::Lifetime => {}
+                GenericParamDefKind::Const => {
+                    self.visit(self.ev.tcx.type_of(param.def_id));
+                }
             }
         }
         self
@@ -1517,12 +1520,15 @@ impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
     fn generics(&mut self) -> &mut Self {
         for param in &self.tcx.generics_of(self.item_def_id).params {
             match param.kind {
+                GenericParamDefKind::Lifetime => {}
                 GenericParamDefKind::Type { has_default, .. } => {
                     if has_default {
                         self.visit(self.tcx.type_of(param.def_id));
                     }
                 }
-                GenericParamDefKind::Lifetime => {}
+                GenericParamDefKind::Const => {
+                    self.visit(self.tcx.type_of(param.def_id));
+                }
             }
         }
         self
diff --git a/src/librustc_traits/chalk_context/mod.rs b/src/librustc_traits/chalk_context/mod.rs
index a326d84725a..6420f20a3ea 100644
--- a/src/librustc_traits/chalk_context/mod.rs
+++ b/src/librustc_traits/chalk_context/mod.rs
@@ -32,11 +32,12 @@ use rustc::traits::{
     InEnvironment,
     ChalkCanonicalGoal,
 };
-use rustc::ty::{self, TyCtxt};
+use rustc::ty::{self, TyCtxt, InferConst};
 use rustc::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 use rustc::ty::query::Providers;
 use rustc::ty::subst::{Kind, UnpackedKind};
 use rustc_data_structures::sync::Lrc;
+use rustc::mir::interpret::ConstValue;
 use syntax_pos::DUMMY_SP;
 
 use std::fmt::{self, Debug};
@@ -287,6 +288,16 @@ impl context::ContextOps<ChalkArenas<'gcx>> for ChalkContext<'cx, 'gcx> {
                     }
                     _ => false,
                 },
+                UnpackedKind::Const(ct) => match ct {
+                    ty::LazyConst::Evaluated(ty::Const {
+                        val: ConstValue::Infer(InferConst::Canonical(debruijn, bound_ct)),
+                        ..
+                    }) => {
+                        debug_assert_eq!(*debruijn, ty::INNERMOST);
+                        cvar == *bound_ct
+                    }
+                    _ => false,
+                }
             })
     }
 
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 5dbcf908020..be708c78a0d 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -3,7 +3,7 @@
 //! instance of `AstConv`.
 
 use errors::{Applicability, DiagnosticId};
-use crate::hir::{self, GenericArg, GenericArgs};
+use crate::hir::{self, GenericArg, GenericArgs, ExprKind};
 use crate::hir::def::Def;
 use crate::hir::def_id::DefId;
 use crate::hir::HirVec;
@@ -16,6 +16,7 @@ use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable};
 use rustc::ty::{GenericParamDef, GenericParamDefKind};
 use rustc::ty::subst::{Kind, Subst, InternalSubsts, SubstsRef};
 use rustc::ty::wf::object_region_bounds;
+use rustc::mir::interpret::ConstValue;
 use rustc_data_structures::sync::Lrc;
 use rustc_target::spec::abi;
 use crate::require_c_abi_if_c_variadic;
@@ -273,6 +274,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
         let param_counts = def.own_counts();
         let arg_counts = args.own_counts();
         let infer_lifetimes = position != GenericArgPosition::Type && arg_counts.lifetimes == 0;
+        let infer_consts = position != GenericArgPosition::Type && arg_counts.consts == 0;
 
         let mut defaults: ty::GenericParamCount = Default::default();
         for param in &def.params {
@@ -281,6 +283,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                 GenericParamDefKind::Type { has_default, .. } => {
                     defaults.types += has_default as usize
                 }
+                GenericParamDefKind::Const => {
+                    // FIXME(const_generics:defaults)
+                }
             };
         }
 
@@ -311,11 +316,15 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
             }
         }
 
-        let check_kind_count = |kind,
-                                required,
-                                permitted,
-                                provided,
-                                offset| {
+        let check_kind_count = |kind, required, permitted, provided, offset| {
+            debug!(
+                "check_kind_count: kind: {} required: {} permitted: {} provided: {} offset: {}",
+                kind,
+                required,
+                permitted,
+                provided,
+                offset
+            );
             // We enforce the following: `required` <= `provided` <= `permitted`.
             // For kinds without defaults (i.e., lifetimes), `required == permitted`.
             // For other kinds (i.e., types), `permitted` may be greater than `required`.
@@ -384,6 +393,17 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                 0,
             );
         }
+        // FIXME(const_generics:defaults)
+        if !infer_consts || arg_counts.consts > param_counts.consts {
+            check_kind_count(
+                "const",
+                param_counts.consts,
+                param_counts.consts,
+                arg_counts.consts,
+                arg_counts.lifetimes + arg_counts.types,
+            );
+        }
+        // Note that type errors are currently be emitted *after* const errors.
         if !infer_types
             || arg_counts.types > param_counts.types - defaults.types - has_self as usize {
             check_kind_count(
@@ -495,7 +515,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                     (Some(&arg), Some(&param)) => {
                         match (arg, &param.kind) {
                             (GenericArg::Lifetime(_), GenericParamDefKind::Lifetime)
-                            | (GenericArg::Type(_), GenericParamDefKind::Type { .. }) => {
+                            | (GenericArg::Type(_), GenericParamDefKind::Type { .. })
+                            | (GenericArg::Const(_), GenericParamDefKind::Const) => {
                                 substs.push(provided_kind(param, arg));
                                 args.next();
                                 params.next();
@@ -606,6 +627,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                     (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
                         self.ast_ty_to_ty(&ty).into()
                     }
+                    (GenericParamDefKind::Const, GenericArg::Const(ct)) => {
+                        self.ast_const_to_const(&ct.value, tcx.type_of(param.def_id)).into()
+                    }
                     _ => unreachable!(),
                 }
             },
@@ -654,6 +678,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                             tcx.types.err.into()
                         }
                     }
+                    GenericParamDefKind::Const => {
+                        // FIXME(const_generics:defaults)
+                        // We've already errored above about the mismatch.
+                        tcx.types.err.into()
+                    }
                 }
             },
         );
@@ -1609,6 +1638,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
             // Case 3. Reference to a top-level value.
             Def::Fn(def_id) |
             Def::Const(def_id) |
+            Def::ConstParam(def_id) |
             Def::Static(def_id, _) => {
                 path_segs.push(PathSeg(def_id, last));
             }
@@ -1797,10 +1827,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                 self.associated_path_to_ty(ast_ty.hir_id, ast_ty.span, ty, def, segment, false).0
             }
             hir::TyKind::Array(ref ty, ref length) => {
-                let length_def_id = tcx.hir().local_def_id_from_hir_id(length.hir_id);
-                let substs = InternalSubsts::identity_for_item(tcx, length_def_id);
-                let length = ty::LazyConst::Unevaluated(length_def_id, substs);
-                let length = tcx.mk_lazy_const(length);
+                let length = self.ast_const_to_const(length, tcx.types.usize);
                 let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(&ty), length));
                 self.normalize_ty(ast_ty.span, array_ty)
             }
@@ -1837,6 +1864,42 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
         result_ty
     }
 
+    pub fn ast_const_to_const(
+        &self,
+        ast_const: &hir::AnonConst,
+        ty: Ty<'tcx>
+    ) -> &'tcx ty::LazyConst<'tcx> {
+        debug!("ast_const_to_const(id={:?}, ast_const={:?})", ast_const.hir_id, ast_const);
+
+        let tcx = self.tcx();
+        let def_id = tcx.hir().local_def_id_from_hir_id(ast_const.hir_id);
+
+        let mut lazy_const = ty::LazyConst::Unevaluated(
+            def_id,
+            InternalSubsts::identity_for_item(tcx, def_id),
+        );
+
+        let expr = &tcx.hir().body(ast_const.body).value;
+        if let ExprKind::Path(ref qpath) = expr.node {
+            if let hir::QPath::Resolved(_, ref path) = qpath {
+                if let Def::ConstParam(def_id) = path.def {
+                    let node_id = tcx.hir().as_local_node_id(def_id).unwrap();
+                    let item_id = tcx.hir().get_parent_node(node_id);
+                    let item_def_id = tcx.hir().local_def_id(item_id);
+                    let generics = tcx.generics_of(item_def_id);
+                    let index = generics.param_def_id_to_index[&tcx.hir().local_def_id(node_id)];
+                    let name = tcx.hir().name(node_id).as_interned_str();
+                    lazy_const = ty::LazyConst::Evaluated(ty::Const {
+                        val: ConstValue::Param(ty::ParamConst::new(index, name)),
+                        ty,
+                    })
+                }
+            }
+        };
+
+        tcx.mk_lazy_const(lazy_const)
+    }
+
     pub fn impl_trait_ty_to_ty(
         &self,
         def_id: DefId,
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index db89b32be7b..f7396cbd42f 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -99,11 +99,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let substs = base_substs.extend_to(self.tcx,expr_def_id, |param, _| {
             match param.kind {
                 GenericParamDefKind::Lifetime => {
-                    span_bug!(expr.span, "closure has region param")
+                    span_bug!(expr.span, "closure has lifetime param")
                 }
-                GenericParamDefKind::Type {..} => {
-                    self.infcx
-                        .next_ty_var(TypeVariableOrigin::ClosureSynthetic(expr.span)).into()
+                GenericParamDefKind::Type { .. } => {
+                    self.infcx.next_ty_var(TypeVariableOrigin::ClosureSynthetic(expr.span)).into()
+                }
+                GenericParamDefKind::Const => {
+                    span_bug!(expr.span, "closure has const param")
                 }
             }
         });
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 59766e7e47d..32640d7d9a8 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -6,7 +6,7 @@ use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
 use rustc::ty::error::{ExpectedFound, TypeError};
 use rustc::ty::subst::{Subst, InternalSubsts, SubstsRef};
 use rustc::util::common::ErrorReported;
-use errors::Applicability;
+use errors::{Applicability, DiagnosticId};
 
 use syntax_pos::Span;
 
@@ -576,55 +576,78 @@ fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     Ok(())
 }
 
-fn compare_number_of_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                        impl_m: &ty::AssociatedItem,
-                                        impl_m_span: Span,
-                                        trait_m: &ty::AssociatedItem,
-                                        trait_item_span: Option<Span>)
-                                        -> Result<(), ErrorReported> {
-    let impl_m_generics = tcx.generics_of(impl_m.def_id);
-    let trait_m_generics = tcx.generics_of(trait_m.def_id);
-    let num_impl_m_type_params = impl_m_generics.own_counts().types;
-    let num_trait_m_type_params = trait_m_generics.own_counts().types;
-
-    if num_impl_m_type_params != num_trait_m_type_params {
-        let impl_m_node_id = tcx.hir().as_local_node_id(impl_m.def_id).unwrap();
-        let impl_m_item = tcx.hir().expect_impl_item(impl_m_node_id);
-        let span = if impl_m_item.generics.params.is_empty()
-            || impl_m_item.generics.span.is_dummy()  // impl Trait in argument position (#55374)
-        {
-            impl_m_span
-        } else {
-            impl_m_item.generics.span
-        };
+fn compare_number_of_generics<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    impl_: &ty::AssociatedItem,
+    impl_span: Span,
+    trait_: &ty::AssociatedItem,
+    trait_span: Option<Span>,
+) -> Result<(), ErrorReported> {
+    let trait_own_counts = tcx.generics_of(trait_.def_id).own_counts();
+    let impl_own_counts = tcx.generics_of(impl_.def_id).own_counts();
+
+    let matchings = [
+        ("type", trait_own_counts.types, impl_own_counts.types),
+        ("const", trait_own_counts.consts, impl_own_counts.consts),
+    ];
+
+    let mut err_occurred = false;
+    for &(kind, trait_count, impl_count) in &matchings {
+        if impl_count != trait_count {
+            err_occurred = true;
+
+            let impl_node_id = tcx.hir().as_local_node_id(impl_.def_id).unwrap();
+            let impl_item = tcx.hir().expect_impl_item(impl_node_id);
+            let span = if impl_item.generics.params.is_empty()
+                || impl_item.generics.span.is_dummy() { // argument position impl Trait (#55374)
+                impl_span
+            } else {
+                impl_item.generics.span
+            };
 
-        let mut err = struct_span_err!(tcx.sess, span, E0049,
-            "method `{}` has {} but its trait declaration has {}",
-            trait_m.ident,
-            potentially_plural_count(num_impl_m_type_params, "type parameter"),
-            potentially_plural_count(num_trait_m_type_params, "type parameter")
-        );
+            let mut err = tcx.sess.struct_span_err_with_code(
+                span,
+                &format!(
+                    "method `{}` has {} {kind} parameter{} but its trait \
+                     declaration has {} {kind} parameter{}",
+                    trait_.ident,
+                    impl_count,
+                    if impl_count != 1 { "s" } else { "" },
+                    trait_count,
+                    if trait_count != 1 { "s" } else { "" },
+                    kind = kind,
+                ),
+                DiagnosticId::Error("E0049".into()),
+            );
 
-        let mut suffix = None;
+            let mut suffix = None;
 
-        if let Some(span) = trait_item_span {
-            err.span_label(span, format!("expected {}",
-                potentially_plural_count(num_trait_m_type_params, "type parameter")));
-        } else {
-            suffix = Some(format!(", expected {}", num_trait_m_type_params));
-        }
-
-        err.span_label(span,
-                       format!("found {}{}",
-                           potentially_plural_count(num_impl_m_type_params, "type parameter"),
-                           suffix.as_ref().map(|s| &s[..]).unwrap_or("")));
+            if let Some(span) = trait_span {
+                err.span_label(
+                    span,
+                    format!("expected {} {} parameter{}", trait_count, kind,
+                        if trait_count != 1 { "s" } else { "" })
+                );
+            } else {
+                suffix = Some(format!(", expected {}", trait_count));
+            }
 
-        err.emit();
+            err.span_label(
+                span,
+                format!("found {} {} parameter{}{}", impl_count, kind,
+                    if impl_count != 1 { "s" } else { "" },
+                    suffix.unwrap_or_else(|| String::new())),
+            );
 
-        return Err(ErrorReported);
+            err.emit();
+        }
     }
 
-    Ok(())
+    if err_occurred {
+        Err(ErrorReported)
+    } else {
+        Ok(())
+    }
 }
 
 fn compare_number_of_method_arguments<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -725,12 +748,12 @@ fn compare_synthetic_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let trait_m_generics = tcx.generics_of(trait_m.def_id);
     let impl_m_type_params = impl_m_generics.params.iter().filter_map(|param| match param.kind {
         GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)),
-        GenericParamDefKind::Lifetime => None,
+        GenericParamDefKind::Lifetime | GenericParamDefKind::Const => None,
     });
     let trait_m_type_params = trait_m_generics.params.iter().filter_map(|param| {
         match param.kind {
             GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)),
-            GenericParamDefKind::Lifetime => None,
+            GenericParamDefKind::Lifetime | GenericParamDefKind::Const => None,
         }
     });
     for ((impl_def_id, impl_synthetic), (trait_def_id, trait_synthetic))
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index 12c7484f0f9..2184555a07d 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -313,6 +313,9 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>(
         match kind.unpack() {
             UnpackedKind::Lifetime(r) => rcx.sub_regions(origin(), parent_scope, r),
             UnpackedKind::Type(ty) => rcx.type_must_outlive(origin(), ty, parent_scope),
+            UnpackedKind::Const(_) => {
+                // Generic consts don't add constraints.
+            }
         }
     }
     Ok(())
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 996d6cfd568..e0b96ae884f 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -341,6 +341,9 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
                     (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
                         self.to_ty(ty).into()
                     }
+                    (GenericParamDefKind::Const, GenericArg::Const(ct)) => {
+                        self.to_const(&ct.value, self.tcx.type_of(param.def_id)).into()
+                    }
                     _ => unreachable!(),
                 }
             },
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index d81d24e6d2b..8f27b5b7dc8 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -283,8 +283,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // Construct a trait-reference `self_ty : Trait<input_tys>`
         let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| {
             match param.kind {
-                GenericParamDefKind::Lifetime => {}
-                GenericParamDefKind::Type {..} => {
+                GenericParamDefKind::Lifetime | GenericParamDefKind::Const => {}
+                GenericParamDefKind::Type { .. } => {
                     if param.index == 0 {
                         return self_ty.into();
                     } else if let Some(ref input_types) = opt_input_types {
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index a4624eebcba..efae870c3c3 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -1528,7 +1528,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
                             // `impl_self_ty()` for an explanation.
                             self.tcx.types.re_erased.into()
                         }
-                        GenericParamDefKind::Type {..} => self.var_for_def(self.span, param),
+                        GenericParamDefKind::Type { .. }
+                        | GenericParamDefKind::Const => {
+                            self.var_for_def(self.span, param)
+                        }
                     }
                 }
             });
@@ -1545,10 +1548,13 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
         InternalSubsts::for_item(self.tcx, def_id, |param, _| {
             match param.kind {
                 GenericParamDefKind::Lifetime => self.tcx.types.re_erased.into(),
-                GenericParamDefKind::Type {..} => {
+                GenericParamDefKind::Type { .. } => {
                     self.next_ty_var(TypeVariableOrigin::SubstitutionPlaceholder(
                         self.tcx.def_span(def_id))).into()
                 }
+                GenericParamDefKind::Const { .. } => {
+                    unimplemented!() // FIXME(const_generics)
+                }
             }
         })
     }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 183667e2244..301d7d3ac56 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2437,6 +2437,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         ty
     }
 
+    pub fn to_const(&self, ast_c: &hir::AnonConst, ty: Ty<'tcx>) -> &'tcx ty::LazyConst<'tcx> {
+        AstConv::ast_const_to_const(self, ast_c, ty)
+    }
+
     // If the type given by the user has free regions, save it for later, since
     // NLL would like to enforce those. Also pass in types that involve
     // projections, since those can resolve to `'static` bounds (modulo #54940,
@@ -5501,6 +5505,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
                         self.to_ty(ty).into()
                     }
+                    (GenericParamDefKind::Const, GenericArg::Const(ct)) => {
+                        self.to_const(&ct.value, self.tcx.type_of(param.def_id)).into()
+                    }
                     _ => unreachable!(),
                 }
             },
@@ -5528,6 +5535,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                             self.var_for_def(span, param)
                         }
                     }
+                    GenericParamDefKind::Const => {
+                        // FIXME(const_generics:defaults)
+                        // No const parameters were provided, we have to infer them.
+                        self.var_for_def(span, param)
+                    }
                 }
             },
         );
@@ -5685,11 +5697,19 @@ pub fn check_bounds_are_used<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                        generics: &ty::Generics,
                                        ty: Ty<'tcx>) {
     let own_counts = generics.own_counts();
-    debug!("check_bounds_are_used(n_tps={}, ty={:?})", own_counts.types, ty);
+    debug!(
+        "check_bounds_are_used(n_tys={}, n_cts={}, ty={:?})",
+        own_counts.types,
+        own_counts.consts,
+        ty
+    );
+
+    // FIXME(const_generics): we probably want to check the bounds for const parameters too.
 
     if own_counts.types == 0 {
         return;
     }
+
     // Make a vector of booleans initially false, set to true when used.
     let mut types_used = vec![false; own_counts.types];
 
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index b549986777c..a03d33a3ef5 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -81,7 +81,7 @@ use rustc::hir::def_id::DefId;
 use rustc::infer::outlives::env::OutlivesEnvironment;
 use rustc::infer::{self, RegionObligation, SuppressRegionErrors};
 use rustc::ty::adjustment;
-use rustc::ty::subst::SubstsRef;
+use rustc::ty::subst::{SubstsRef, UnpackedKind};
 use rustc::ty::{self, Ty};
 
 use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
@@ -1407,13 +1407,19 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
 
         let origin = infer::ParameterInScope(origin, expr_span);
 
-        for region in substs.regions() {
-            self.sub_regions(origin.clone(), expr_region, region);
-        }
-
-        for ty in substs.types() {
-            let ty = self.resolve_type(ty);
-            self.type_must_outlive(origin.clone(), ty, expr_region);
+        for kind in substs {
+            match kind.unpack() {
+                UnpackedKind::Lifetime(lt) => {
+                    self.sub_regions(origin.clone(), expr_region, lt);
+                }
+                UnpackedKind::Type(ty) => {
+                    let ty = self.resolve_type(ty);
+                    self.type_must_outlive(origin.clone(), ty, expr_region);
+                }
+                UnpackedKind::Const(_) => {
+                    // Const parameters don't impose constraints.
+                }
+            }
         }
     }
 }
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 860fa526a1b..16cf25f0d49 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -6,6 +6,7 @@ use rustc::traits::{self, ObligationCauseCode};
 use rustc::ty::{self, Lift, Ty, TyCtxt, TyKind, GenericParamDefKind, TypeFoldable, ToPredicate};
 use rustc::ty::subst::{Subst, InternalSubsts};
 use rustc::util::nodemap::{FxHashSet, FxHashMap};
+use rustc::mir::interpret::ConstValue;
 use rustc::middle::lang_items;
 use rustc::infer::opaque_types::may_define_existential_type;
 
@@ -436,7 +437,7 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(
     // struct Foo<T = Vec<[u32]>> { .. }
     // Here the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold.
     for param in &generics.params {
-        if let GenericParamDefKind::Type {..} = param.kind {
+        if let GenericParamDefKind::Type { .. } = param.kind {
             if is_our_default(&param) {
                 let ty = fcx.tcx.type_of(param.def_id);
                 // ignore dependent defaults -- that is, where the default of one type
@@ -464,7 +465,7 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(
                 // All regions are identity.
                 fcx.tcx.mk_param_from_def(param)
             }
-            GenericParamDefKind::Type {..} => {
+            GenericParamDefKind::Type { .. } => {
                 // If the param has a default,
                 if is_our_default(param) {
                     let default_ty = fcx.tcx.type_of(param.def_id);
@@ -477,6 +478,10 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(
                 // Mark unwanted params as err.
                 fcx.tcx.types.err.into()
             }
+            GenericParamDefKind::Const => {
+                // FIXME(const_generics:defaults)
+                fcx.tcx.types.err.into()
+            }
         }
     });
     // Now we build the substituted predicates.
@@ -497,6 +502,16 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>(
             fn visit_region(&mut self, _: ty::Region<'tcx>) -> bool {
                 true
             }
+
+            fn visit_const(&mut self, c: &'tcx ty::LazyConst<'tcx>) -> bool {
+                if let ty::LazyConst::Evaluated(ty::Const {
+                    val: ConstValue::Param(param),
+                    ..
+                }) = c {
+                    self.params.insert(param.index);
+                }
+                c.super_visit_with(self)
+            }
         }
         let mut param_count = CountParams::default();
         let has_region = pred.visit_with(&mut param_count);
@@ -617,11 +632,10 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>(
                         for (subst, param) in substs.iter().zip(&generics.params) {
                             match subst.unpack() {
                                 ty::subst::UnpackedKind::Type(ty) => match ty.sty {
-                                    ty::Param(..) => {},
+                                    ty::Param(..) => {}
                                     // prevent `fn foo() -> Foo<u32>` from being defining
                                     _ => {
-                                        tcx
-                                            .sess
+                                        tcx.sess
                                             .struct_span_err(
                                                 span,
                                                 "non-defining existential type use \
@@ -636,8 +650,9 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>(
                                                 ),
                                             )
                                             .emit();
-                                    },
-                                }, // match ty
+                                    }
+                                }
+
                                 ty::subst::UnpackedKind::Lifetime(region) => {
                                     let param_span = tcx.def_span(param.def_id);
                                     if let ty::ReStatic = region {
@@ -658,7 +673,31 @@ fn check_existential_types<'a, 'fcx, 'gcx, 'tcx>(
                                     } else {
                                         seen.entry(region).or_default().push(param_span);
                                     }
-                                },
+                                }
+
+                                ty::subst::UnpackedKind::Const(ct) => match ct {
+                                    ty::LazyConst::Evaluated(ty::Const {
+                                        val: ConstValue::Param(_),
+                                        ..
+                                    }) => {}
+                                    _ => {
+                                        tcx.sess
+                                            .struct_span_err(
+                                                span,
+                                                "non-defining existential type use \
+                                                in defining scope",
+                                            )
+                                            .span_note(
+                                                tcx.def_span(param.def_id),
+                                                &format!(
+                                                    "used non-generic const {} for \
+                                                    generic parameter",
+                                                    ty,
+                                                ),
+                                            )
+                                            .emit();
+                                    }
+                                }
                             } // match subst
                         } // for (subst, param)
                         for (_, spans) in seen {
@@ -942,7 +981,9 @@ fn reject_shadowing_parameters(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) {
     let parent = tcx.generics_of(generics.parent.unwrap());
     let impl_params: FxHashMap<_, _> = parent.params.iter().flat_map(|param| match param.kind {
         GenericParamDefKind::Lifetime => None,
-        GenericParamDefKind::Type {..} => Some((param.name, param.def_id)),
+        GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => {
+            Some((param.name, param.def_id))
+        }
     }).collect();
 
     for method_param in &generics.params {
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 594e29ab9dd..eb4bbe88069 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1004,67 +1004,65 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty
         ast_generics
             .params
             .iter()
-            .filter_map(|param| match param.kind {
-                GenericParamKind::Type {
-                    ref default,
-                    synthetic,
-                    ..
-                } => {
-                    if param.name.ident().name == keywords::SelfUpper.name() {
-                        span_bug!(
-                            param.span,
-                            "`Self` should not be the name of a regular parameter"
-                        );
-                    }
-
-                    if !allow_defaults && default.is_some() {
-                        if !tcx.features().default_type_parameter_fallback {
-                            tcx.lint_hir(
-                                lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
-                                param.hir_id,
+            .filter_map(|param| {
+                let kind = match param.kind {
+                    GenericParamKind::Type {
+                        ref default,
+                        synthetic,
+                        ..
+                    } => {
+                        if param.name.ident().name == keywords::SelfUpper.name() {
+                            span_bug!(
                                 param.span,
-                                &format!(
-                                    "defaults for type parameters are only allowed in \
-                                     `struct`, `enum`, `type`, or `trait` definitions."
-                                ),
+                                "`Self` should not be the name of a regular parameter"
                             );
                         }
-                    }
 
-                    let ty_param = ty::GenericParamDef {
-                        index: type_start + i as u32,
-                        name: param.name.ident().as_interned_str(),
-                        def_id: tcx.hir().local_def_id_from_hir_id(param.hir_id),
-                        pure_wrt_drop: param.pure_wrt_drop,
-                        kind: ty::GenericParamDefKind::Type {
+                        if !allow_defaults && default.is_some() {
+                            if !tcx.features().default_type_parameter_fallback {
+                                tcx.lint_hir(
+                                    lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
+                                    param.hir_id,
+                                    param.span,
+                                    &format!(
+                                        "defaults for type parameters are only allowed in \
+                                        `struct`, `enum`, `type`, or `trait` definitions."
+                                    ),
+                                );
+                            }
+                        }
+
+                        ty::GenericParamDefKind::Type {
                             has_default: default.is_some(),
                             object_lifetime_default: object_lifetime_defaults
                                 .as_ref()
                                 .map_or(rl::Set1::Empty, |o| o[i]),
                             synthetic,
-                        },
-                    };
-                    i += 1;
-                    Some(ty_param)
-                }
-                GenericParamKind::Const { .. } => {
-                    if param.name.ident().name == keywords::SelfUpper.name() {
-                        span_bug!(
-                            param.span,
-                            "`Self` should not be the name of a regular parameter",
-                        );
+                        }
                     }
+                    GenericParamKind::Const { .. } => {
+                        if param.name.ident().name == keywords::SelfUpper.name() {
+                            span_bug!(
+                                param.span,
+                                "`Self` should not be the name of a regular parameter",
+                            );
+                        }
 
-                    // Emit an error, but skip the parameter rather than aborting to
-                    // continue to get other errors.
-                    tcx.sess.struct_span_err(
-                        param.span,
-                        "const generics in any position are currently unsupported",
-                    ).emit();
-                    None
-                }
-                _ => None,
-            }),
+                        ty::GenericParamDefKind::Const
+                    }
+                    _ => return None,
+                };
+
+                let param_def = ty::GenericParamDef {
+                    index: type_start + i as u32,
+                    name: param.name.ident().as_interned_str(),
+                    def_id: tcx.hir().local_def_id_from_hir_id(param.hir_id),
+                    pure_wrt_drop: param.pure_wrt_drop,
+                    kind,
+                };
+                i += 1;
+                Some(param_def)
+            })
     );
 
     // provide junk type parameter defs - the only place that
@@ -1284,44 +1282,111 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> {
             tcx.mk_closure(def_id, substs)
         }
 
-        Node::AnonConst(_) => match tcx.hir().get_by_hir_id(
-            tcx.hir().get_parent_node_by_hir_id(hir_id))
-        {
-            Node::Ty(&hir::Ty {
-                node: hir::TyKind::Array(_, ref constant),
-                ..
-            })
-            | Node::Ty(&hir::Ty {
-                node: hir::TyKind::Typeof(ref constant),
-                ..
-            })
-            | Node::Expr(&hir::Expr {
-                node: ExprKind::Repeat(_, ref constant),
-                ..
-            }) if constant.hir_id == hir_id =>
-            {
-                tcx.types.usize
-            }
+        Node::AnonConst(_) => {
+            let parent_node = tcx.hir().get_by_hir_id(tcx.hir().get_parent_node_by_hir_id(hir_id));
+            match parent_node {
+                Node::Ty(&hir::Ty {
+                    node: hir::TyKind::Array(_, ref constant),
+                    ..
+                })
+                | Node::Ty(&hir::Ty {
+                    node: hir::TyKind::Typeof(ref constant),
+                    ..
+                })
+                | Node::Expr(&hir::Expr {
+                    node: ExprKind::Repeat(_, ref constant),
+                    ..
+                }) if constant.hir_id == hir_id =>
+                {
+                    tcx.types.usize
+                }
 
-            Node::Variant(&Spanned {
-                node:
-                    VariantKind {
-                        disr_expr: Some(ref e),
-                        ..
-                    },
-                ..
-            }) if e.hir_id == hir_id =>
-            {
-                tcx.adt_def(tcx.hir().get_parent_did_by_hir_id(hir_id))
-                    .repr
-                    .discr_type()
-                    .to_ty(tcx)
-            }
+                Node::Variant(&Spanned {
+                    node:
+                        VariantKind {
+                            disr_expr: Some(ref e),
+                            ..
+                        },
+                    ..
+                }) if e.hir_id == hir_id =>
+                {
+                    tcx.adt_def(tcx.hir().get_parent_did_by_hir_id(hir_id))
+                        .repr
+                        .discr_type()
+                        .to_ty(tcx)
+                }
 
-            x => {
-                bug!("unexpected const parent in type_of_def_id(): {:?}", x);
+                Node::Ty(&hir::Ty { node: hir::TyKind::Path(_), .. }) |
+                Node::Expr(&hir::Expr { node: ExprKind::Struct(..), .. }) |
+                Node::Expr(&hir::Expr { node: ExprKind::Path(_), .. }) => {
+                    let path = match parent_node {
+                        Node::Ty(&hir::Ty { node: hir::TyKind::Path(ref path), .. }) |
+                        Node::Expr(&hir::Expr { node: ExprKind::Path(ref path), .. }) => {
+                            path
+                        }
+                        Node::Expr(&hir::Expr { node: ExprKind::Struct(ref path, ..), .. }) => {
+                            &*path
+                        }
+                        _ => unreachable!(),
+                    };
+
+                    match path {
+                        QPath::Resolved(_, ref path) => {
+                            let mut arg_index = 0;
+                            let mut found_const = false;
+                            for seg in &path.segments {
+                                if let Some(generic_args) = &seg.args {
+                                    let args = &generic_args.args;
+                                    for arg in args {
+                                        if let GenericArg::Const(ct) = arg {
+                                            if ct.value.hir_id == hir_id {
+                                                found_const = true;
+                                                break;
+                                            }
+                                            arg_index += 1;
+                                        }
+                                    }
+                                }
+                            }
+                            // Sanity check to make sure everything is as expected.
+                            if !found_const {
+                                bug!("no arg matching AnonConst in path")
+                            }
+                            match path.def {
+                                // We've encountered an `AnonConst` in some path, so we need to
+                                // figure out which generic parameter it corresponds to and return
+                                // the relevant type.
+                                Def::Struct(def_id)
+                                | Def::Union(def_id)
+                                | Def::Enum(def_id)
+                                | Def::Fn(def_id) => {
+                                    let generics = tcx.generics_of(def_id);
+                                    let mut param_index = 0;
+                                    for param in &generics.params {
+                                        if let ty::GenericParamDefKind::Const = param.kind {
+                                            if param_index == arg_index {
+                                                return tcx.type_of(param.def_id);
+                                            }
+                                            param_index += 1;
+                                        }
+                                    }
+                                    // This is no generic parameter associated with the arg. This is
+                                    // probably from an extra arg where one is not needed.
+                                    return tcx.types.err;
+                                }
+                                Def::Err => tcx.types.err,
+                                x => bug!("unexpected const parent path def {:?}", x),
+                            }
+                        }
+                        x => bug!("unexpected const parent path {:?}", x),
+                    }
+                }
+
+                x => {
+                    bug!("unexpected const parent in type_of_def_id(): {:?}", x);
+                }
             }
-        },
+        }
 
         Node::GenericParam(param) => match &param.kind {
             hir::GenericParamKind::Type { default: Some(ref ty), .. } |
diff --git a/src/librustc_typeck/constrained_type_params.rs b/src/librustc_typeck/constrained_type_params.rs
index 6a530f454d2..4b922c34038 100644
--- a/src/librustc_typeck/constrained_type_params.rs
+++ b/src/librustc_typeck/constrained_type_params.rs
@@ -1,6 +1,7 @@
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::fold::{TypeFoldable, TypeVisitor};
 use rustc::util::nodemap::FxHashSet;
+use rustc::mir::interpret::ConstValue;
 use syntax::source_map::Span;
 
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
@@ -14,6 +15,10 @@ impl From<ty::EarlyBoundRegion> for Parameter {
     fn from(param: ty::EarlyBoundRegion) -> Self { Parameter(param.index) }
 }
 
+impl From<ty::ParamConst> for Parameter {
+    fn from(param: ty::ParamConst) -> Self { Parameter(param.index) }
+}
+
 /// Returns the set of parameters constrained by the impl header.
 pub fn parameters_for_impl<'tcx>(impl_self_ty: Ty<'tcx>,
                                  impl_trait_ref: Option<ty::TraitRef<'tcx>>)
@@ -72,6 +77,16 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector {
         }
         false
     }
+
+    fn visit_const(&mut self, c: &'tcx ty::LazyConst<'tcx>) -> bool {
+        if let ty::LazyConst::Evaluated(ty::Const {
+            val: ConstValue::Param(data),
+            ..
+        }) = c {
+            self.parameters.push(Parameter::from(*data));
+        }
+        false
+    }
 }
 
 pub fn identify_constrained_type_params<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>,
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index feff79dc3f5..399cd6f890c 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -423,7 +423,7 @@ impl Foo for Bar {
 
 E0049: r##"
 This error indicates that an attempted implementation of a trait method
-has the wrong number of type parameters.
+has the wrong number of type or const parameters.
 
 For example, the trait below has a method `foo` with a type parameter `T`,
 but the implementation of `foo` for the type `Bar` is missing this parameter:
@@ -1032,6 +1032,7 @@ enum NightsWatch {}
 ```
 "##,
 
+// FIXME(const_generics:docs): example of inferring const parameter.
 E0087: r##"
 #### Note: this error code is no longer emitted by the compiler.
 
@@ -1152,8 +1153,8 @@ fn main() {
 "##,
 
 E0091: r##"
-You gave an unnecessary type parameter in a type alias. Erroneous code
-example:
+You gave an unnecessary type or const parameter in a type alias. Erroneous
+code example:
 
 ```compile_fail,E0091
 type Foo<T> = u32; // error: type parameter `T` is unused
@@ -1161,7 +1162,7 @@ type Foo<T> = u32; // error: type parameter `T` is unused
 type Foo<A,B> = Box<A>; // error: type parameter `B` is unused
 ```
 
-Please check you didn't write too many type parameters. Example:
+Please check you didn't write too many parameters. Example:
 
 ```
 type Foo = u32; // ok!
diff --git a/src/librustc_typeck/impl_wf_check.rs b/src/librustc_typeck/impl_wf_check.rs
index b79277ffbbc..5677f2c94d8 100644
--- a/src/librustc_typeck/impl_wf_check.rs
+++ b/src/librustc_typeck/impl_wf_check.rs
@@ -120,7 +120,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     for param in &impl_generics.params {
         match param.kind {
             // Disallow ANY unconstrained type parameters.
-            ty::GenericParamDefKind::Type {..} => {
+            ty::GenericParamDefKind::Type { .. } => {
                 let param_ty = ty::ParamTy::for_def(param);
                 if !input_parameters.contains(&ctp::Parameter::from(param_ty)) {
                     report_unused_parameter(tcx,
@@ -139,6 +139,15 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                             &param.name.to_string());
                 }
             }
+            ty::GenericParamDefKind::Const => {
+                let param_ct = ty::ParamConst::for_def(param);
+                if !input_parameters.contains(&ctp::Parameter::from(param_ct)) {
+                    report_unused_parameter(tcx,
+                                           tcx.def_span(param.def_id),
+                                           "const",
+                                           &param_ct.to_string());
+                }
+            }
         }
     }
 
diff --git a/src/librustc_typeck/outlives/mod.rs b/src/librustc_typeck/outlives/mod.rs
index b3634d37cc2..1ab414c1f01 100644
--- a/src/librustc_typeck/outlives/mod.rs
+++ b/src/librustc_typeck/outlives/mod.rs
@@ -98,14 +98,22 @@ fn inferred_outlives_crate<'tcx>(
         .map(|(&def_id, set)| {
             let vec: Vec<ty::Predicate<'tcx>> = set
                 .iter()
-                .map(
+                .filter_map(
                     |ty::OutlivesPredicate(kind1, region2)| match kind1.unpack() {
-                        UnpackedKind::Type(ty1) => ty::Predicate::TypeOutlives(ty::Binder::bind(
-                            ty::OutlivesPredicate(ty1, region2),
-                        )),
-                        UnpackedKind::Lifetime(region1) => ty::Predicate::RegionOutlives(
-                            ty::Binder::bind(ty::OutlivesPredicate(region1, region2)),
-                        ),
+                        UnpackedKind::Type(ty1) => {
+                            Some(ty::Predicate::TypeOutlives(ty::Binder::bind(
+                                ty::OutlivesPredicate(ty1, region2)
+                            )))
+                        }
+                        UnpackedKind::Lifetime(region1) => {
+                            Some(ty::Predicate::RegionOutlives(
+                                ty::Binder::bind(ty::OutlivesPredicate(region1, region2))
+                            ))
+                        }
+                        UnpackedKind::Const(_) => {
+                            // Generic consts don't impose any constraints.
+                            None
+                        }
                     },
                 ).collect();
             (def_id, Lrc::new(vec))
diff --git a/src/librustc_typeck/outlives/utils.rs b/src/librustc_typeck/outlives/utils.rs
index c886c7a4ffc..ee552ca9cbb 100644
--- a/src/librustc_typeck/outlives/utils.rs
+++ b/src/librustc_typeck/outlives/utils.rs
@@ -118,6 +118,10 @@ pub fn insert_outlives_predicate<'tcx>(
             }
             required_predicates.insert(ty::OutlivesPredicate(kind, outlived_region));
         }
+
+        UnpackedKind::Const(_) => {
+            // Generic consts don't impose any constraints.
+        }
     }
 }
 
diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs
index d8d93b462a9..49d11150689 100644
--- a/src/librustc_typeck/variance/constraints.rs
+++ b/src/librustc_typeck/variance/constraints.rs
@@ -4,7 +4,8 @@
 //! We walk the set of items and, for each member, generate new constraints.
 
 use hir::def_id::DefId;
-use rustc::ty::subst::{UnpackedKind, SubstsRef};
+use rustc::mir::interpret::ConstValue;
+use rustc::ty::subst::{SubstsRef, UnpackedKind};
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::hir;
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
@@ -229,12 +230,19 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
 
         // Trait are always invariant so we can take advantage of that.
         let variance_i = self.invariant(variance);
-        for ty in substs.types() {
-            self.add_constraints_from_ty(current, ty, variance_i);
-        }
 
-        for region in substs.regions() {
-            self.add_constraints_from_region(current, region, variance_i);
+        for k in substs {
+            match k.unpack() {
+                UnpackedKind::Lifetime(lt) => {
+                    self.add_constraints_from_region(current, lt, variance_i)
+                }
+                UnpackedKind::Type(ty) => {
+                    self.add_constraints_from_ty(current, ty, variance_i)
+                }
+                UnpackedKind::Const(ct) => {
+                    self.add_constraints_from_const(current, ct, variance_i)
+                }
+            }
         }
     }
 
@@ -267,7 +275,11 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                 self.add_constraints_from_mt(current, &ty::TypeAndMut { ty, mutbl }, variance);
             }
 
-            ty::Array(typ, _) |
+            ty::Array(typ, len) => {
+                self.add_constraints_from_ty(current, typ, variance);
+                self.add_constraints_from_const(current, len, variance);
+            }
+
             ty::Slice(typ) => {
                 self.add_constraints_from_ty(current, typ, variance);
             }
@@ -383,6 +395,9 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                 UnpackedKind::Type(ty) => {
                     self.add_constraints_from_ty(current, ty, variance_i)
                 }
+                UnpackedKind::Const(ct) => {
+                    self.add_constraints_from_const(current, ct, variance_i)
+                }
             }
         }
     }
@@ -434,6 +449,26 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
         }
     }
 
+    fn add_constraints_from_const(
+        &mut self,
+        current: &CurrentItem,
+        ct: &ty::LazyConst<'tcx>,
+        variance: VarianceTermPtr<'a>
+    ) {
+        debug!(
+            "add_constraints_from_const(ct={:?}, variance={:?})",
+            ct,
+            variance
+        );
+
+        if let ty::LazyConst::Evaluated(ct) = ct {
+            self.add_constraints_from_ty(current, ct.ty, variance);
+            if let ConstValue::Param(ref data) = ct.val {
+                self.add_constraint(current, data.index, variance);
+            }
+        }
+    }
+
     /// Adds constraints appropriate for a mutability-type pair
     /// appearing in a context with ambient variance `variance`
     fn add_constraints_from_mt(&mut self,
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index c64a73fa308..5d0d76507bd 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1482,6 +1482,9 @@ impl<'tcx> Clean<GenericParamDef> for ty::GenericParamDef {
                     synthetic: None,
                 })
             }
+            ty::GenericParamDefKind::Const { .. } => {
+                unimplemented!() // FIXME(const_generics)
+            }
         };
 
         GenericParamDef {
@@ -1629,6 +1632,9 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics,
                 }
                 Some(param.clean(cx))
             }
+            ty::GenericParamDefKind::Const { .. } => {
+                unimplemented!() // FIXME(const_generics)
+            }
         }).collect::<Vec<GenericParamDef>>();
 
         let mut where_predicates = preds.predicates.iter()
@@ -1678,6 +1684,9 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics,
                         .flat_map(|param| match param.kind {
                             ty::GenericParamDefKind::Lifetime => Some(param.clean(cx)),
                             ty::GenericParamDefKind::Type { .. } => None,
+                            ty::GenericParamDefKind::Const { .. } => {
+                                unimplemented!() // FIXME(const_generics)
+                            }
                         }).chain(simplify::ty_params(stripped_typarams).into_iter())
                         .collect(),
             where_predicates: simplify::where_clauses(cx, where_predicates),
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index fdb071638b7..07cfdde4a4e 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -221,6 +221,9 @@ impl<'a, 'tcx, 'rcx> DocContext<'a, 'tcx, 'rcx> {
                 ty::GenericParamDefKind::Type { .. } => {
                     args.push(hir::GenericArg::Type(self.ty_param_to_ty(param.clone())));
                 }
+                ty::GenericParamDefKind::Const { .. } => {
+                    unimplemented!() // FIXME(const_generics)
+                }
             }
         }
 
diff --git a/src/test/ui/const-generics/const-expression-parameter.rs b/src/test/ui/const-generics/const-expression-parameter.rs
index f4e9008dbd0..662c7b767ba 100644
--- a/src/test/ui/const-generics/const-expression-parameter.rs
+++ b/src/test/ui/const-generics/const-expression-parameter.rs
@@ -1,23 +1,22 @@
 #![feature(const_generics)]
 //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
 
-fn u32_identity<const X: u32>() -> u32 {
-    //~^ ERROR const generics in any position are currently unsupported
+fn i32_identity<const X: i32>() -> i32 {
     5
 }
 
 fn foo_a() {
-    u32_identity::<-1>(); //~ ERROR expected identifier, found `<-`
+    i32_identity::<-1>(); //~ ERROR expected identifier, found `<-`
 }
 
 fn foo_b() {
-    u32_identity::<1 + 2>(); //~ ERROR expected one of `,` or `>`, found `+`
+    i32_identity::<1 + 2>(); //~ ERROR expected one of `,` or `>`, found `+`
 }
 
 fn foo_c() {
-    u32_identity::< -1 >(); // ok
+    i32_identity::< -1 >(); // ok
 }
 
 fn main() {
-    u32_identity::<5>(); // ok
+    i32_identity::<5>(); // ok
 }
diff --git a/src/test/ui/const-generics/const-expression-parameter.stderr b/src/test/ui/const-generics/const-expression-parameter.stderr
index 1dd3a960316..2741d621256 100644
--- a/src/test/ui/const-generics/const-expression-parameter.stderr
+++ b/src/test/ui/const-generics/const-expression-parameter.stderr
@@ -1,13 +1,13 @@
 error: expected identifier, found `<-`
-  --> $DIR/const-expression-parameter.rs:10:19
+  --> $DIR/const-expression-parameter.rs:9:19
    |
-LL |     u32_identity::<-1>(); //~ ERROR expected identifier, found `<-`
+LL |     i32_identity::<-1>(); //~ ERROR expected identifier, found `<-`
    |                   ^^ expected identifier
 
 error: expected one of `,` or `>`, found `+`
-  --> $DIR/const-expression-parameter.rs:14:22
+  --> $DIR/const-expression-parameter.rs:13:22
    |
-LL |     u32_identity::<1 + 2>(); //~ ERROR expected one of `,` or `>`, found `+`
+LL |     i32_identity::<1 + 2>(); //~ ERROR expected one of `,` or `>`, found `+`
    |                      ^ expected one of `,` or `>` here
 
 warning: the feature `const_generics` is incomplete and may cause the compiler to crash
@@ -16,11 +16,5 @@ warning: the feature `const_generics` is incomplete and may cause the compiler t
 LL | #![feature(const_generics)]
    |            ^^^^^^^^^^^^^^
 
-error: const generics in any position are currently unsupported
-  --> $DIR/const-expression-parameter.rs:4:23
-   |
-LL | fn u32_identity<const X: u32>() -> u32 {
-   |                       ^
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/const-fn-with-const-param.rs b/src/test/ui/const-generics/const-fn-with-const-param.rs
index 052d723d96e..f36bf3875c3 100644
--- a/src/test/ui/const-generics/const-fn-with-const-param.rs
+++ b/src/test/ui/const-generics/const-fn-with-const-param.rs
@@ -3,7 +3,6 @@
 
 const fn const_u32_identity<const X: u32>() -> u32 {
     //~^ ERROR const parameters are not permitted in `const fn`
-    //~^^ ERROR const generics in any position are currently unsupported
     X
 }
 
diff --git a/src/test/ui/const-generics/const-fn-with-const-param.stderr b/src/test/ui/const-generics/const-fn-with-const-param.stderr
index a08ebfb0d97..94d2afa25b4 100644
--- a/src/test/ui/const-generics/const-fn-with-const-param.stderr
+++ b/src/test/ui/const-generics/const-fn-with-const-param.stderr
@@ -9,16 +9,9 @@ error: const parameters are not permitted in `const fn`
    |
 LL | / const fn const_u32_identity<const X: u32>() -> u32 {
 LL | |     //~^ ERROR const parameters are not permitted in `const fn`
-LL | |     //~^^ ERROR const generics in any position are currently unsupported
 LL | |     X
 LL | | }
    | |_^
 
-error: const generics in any position are currently unsupported
-  --> $DIR/const-fn-with-const-param.rs:4:35
-   |
-LL | const fn const_u32_identity<const X: u32>() -> u32 {
-   |                                   ^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
diff --git a/src/test/ui/const-generics/const-param-before-other-params.rs b/src/test/ui/const-generics/const-param-before-other-params.rs
index 47f826789e0..188b5dce31e 100644
--- a/src/test/ui/const-generics/const-param-before-other-params.rs
+++ b/src/test/ui/const-generics/const-param-before-other-params.rs
@@ -1,14 +1,12 @@
 #![feature(const_generics)]
 //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
 
-fn foo<const X: (), T>(_: T) {
+fn foo<const X: (), T>(_: &T) {
     //~^ ERROR type parameters must be declared prior to const parameters
-    //~^^ ERROR const generics in any position are currently unsupported
 }
 
 fn bar<const X: (), 'a>(_: &'a ()) {
     //~^ ERROR lifetime parameters must be declared prior to const parameters
-    //~^^ ERROR const generics in any position are currently unsupported
 }
 
 fn main() {}
diff --git a/src/test/ui/const-generics/const-param-before-other-params.stderr b/src/test/ui/const-generics/const-param-before-other-params.stderr
index a43415d0e5a..78f129e79ea 100644
--- a/src/test/ui/const-generics/const-param-before-other-params.stderr
+++ b/src/test/ui/const-generics/const-param-before-other-params.stderr
@@ -7,26 +7,14 @@ LL | #![feature(const_generics)]
 error: type parameters must be declared prior to const parameters
   --> $DIR/const-param-before-other-params.rs:4:21
    |
-LL | fn foo<const X: (), T>(_: T) {
+LL | fn foo<const X: (), T>(_: &T) {
    |       --------------^- help: reorder the parameters: lifetimes, then types, then consts: `<T, const X: ()>`
 
 error: lifetime parameters must be declared prior to const parameters
-  --> $DIR/const-param-before-other-params.rs:9:21
+  --> $DIR/const-param-before-other-params.rs:8:21
    |
 LL | fn bar<const X: (), 'a>(_: &'a ()) {
    |       --------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, const X: ()>`
 
-error: const generics in any position are currently unsupported
-  --> $DIR/const-param-before-other-params.rs:4:14
-   |
-LL | fn foo<const X: (), T>(_: T) {
-   |              ^
-
-error: const generics in any position are currently unsupported
-  --> $DIR/const-param-before-other-params.rs:9:14
-   |
-LL | fn bar<const X: (), 'a>(_: &'a ()) {
-   |              ^
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/const-generics/const-param-from-outer-fn.rs b/src/test/ui/const-generics/const-param-from-outer-fn.rs
index 5a8dd92086f..6534bcf5ce6 100644
--- a/src/test/ui/const-generics/const-param-from-outer-fn.rs
+++ b/src/test/ui/const-generics/const-param-from-outer-fn.rs
@@ -2,7 +2,6 @@
 //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
 
 fn foo<const X: u32>() {
-    //~^ ERROR const generics in any position are currently unsupported
     fn bar() -> u32 {
         X //~ ERROR can't use generic parameters from outer function
     }
diff --git a/src/test/ui/const-generics/const-param-from-outer-fn.stderr b/src/test/ui/const-generics/const-param-from-outer-fn.stderr
index b238b3a2aa4..f40b527d716 100644
--- a/src/test/ui/const-generics/const-param-from-outer-fn.stderr
+++ b/src/test/ui/const-generics/const-param-from-outer-fn.stderr
@@ -5,22 +5,15 @@ LL | #![feature(const_generics)]
    |            ^^^^^^^^^^^^^^
 
 error[E0401]: can't use generic parameters from outer function
-  --> $DIR/const-param-from-outer-fn.rs:7:9
+  --> $DIR/const-param-from-outer-fn.rs:6:9
    |
 LL | fn foo<const X: u32>() {
    |              - const variable from outer function
-LL |     //~^ ERROR const generics in any position are currently unsupported
 LL |     fn bar() -> u32 {
    |        --- try adding a local generic parameter in this method instead
 LL |         X //~ ERROR can't use generic parameters from outer function
    |         ^ use of generic parameter from outer function
 
-error: const generics in any position are currently unsupported
-  --> $DIR/const-param-from-outer-fn.rs:4:14
-   |
-LL | fn foo<const X: u32>() {
-   |              ^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0401`.
diff --git a/src/test/ui/const-generics/const-parameter-uppercase-lint.rs b/src/test/ui/const-generics/const-parameter-uppercase-lint.rs
index 37fe9af98b3..164205dd75c 100644
--- a/src/test/ui/const-generics/const-parameter-uppercase-lint.rs
+++ b/src/test/ui/const-generics/const-parameter-uppercase-lint.rs
@@ -4,5 +4,7 @@
 #![deny(non_upper_case_globals)]
 
 fn noop<const x: u32>() {
-    //~^ ERROR const generics in any position are currently unsupported
+    //~^ ERROR const parameter `x` should have an upper case name
 }
+
+fn main() {}
diff --git a/src/test/ui/const-generics/const-parameter-uppercase-lint.stderr b/src/test/ui/const-generics/const-parameter-uppercase-lint.stderr
index 9683e91cef3..190798d202b 100644
--- a/src/test/ui/const-generics/const-parameter-uppercase-lint.stderr
+++ b/src/test/ui/const-generics/const-parameter-uppercase-lint.stderr
@@ -4,16 +4,17 @@ warning: the feature `const_generics` is incomplete and may cause the compiler t
 LL | #![feature(const_generics)]
    |            ^^^^^^^^^^^^^^
 
-error[E0601]: `main` function not found in crate `const_parameter_uppercase_lint`
-   |
-   = note: consider adding a `main` function to `$DIR/const-parameter-uppercase-lint.rs`
-
-error: const generics in any position are currently unsupported
+error: const parameter `x` should have an upper case name
   --> $DIR/const-parameter-uppercase-lint.rs:6:15
    |
 LL | fn noop<const x: u32>() {
-   |               ^
+   |               ^ help: convert the identifier to upper case: `X`
+   |
+note: lint level defined here
+  --> $DIR/const-parameter-uppercase-lint.rs:4:9
+   |
+LL | #![deny(non_upper_case_globals)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0601`.
diff --git a/src/test/ui/derives/deriving-with-repr-packed.stderr b/src/test/ui/derives/deriving-with-repr-packed.stderr
index 4ab14a1df84..9d96908a056 100644
--- a/src/test/ui/derives/deriving-with-repr-packed.stderr
+++ b/src/test/ui/derives/deriving-with-repr-packed.stderr
@@ -1,4 +1,4 @@
-error: #[derive] can't be used on a #[repr(packed)] struct with type parameters (error E0133)
+error: #[derive] can't be used on a #[repr(packed)] struct with type or const parameters (error E0133)
   --> $DIR/deriving-with-repr-packed.rs:8:16
    |
 LL | #[derive(Copy, Clone, PartialEq, Eq)]
@@ -12,7 +12,7 @@ LL | #![deny(safe_packed_borrows)]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043>
 
-error: #[derive] can't be used on a #[repr(packed)] struct with type parameters (error E0133)
+error: #[derive] can't be used on a #[repr(packed)] struct with type or const parameters (error E0133)
   --> $DIR/deriving-with-repr-packed.rs:8:23
    |
 LL | #[derive(Copy, Clone, PartialEq, Eq)]
diff --git a/src/test/ui/feature-gates/feature-gate-const_generics.rs b/src/test/ui/feature-gates/feature-gate-const_generics.rs
index 907e00b11e5..fe1ded1c4bb 100644
--- a/src/test/ui/feature-gates/feature-gate-const_generics.rs
+++ b/src/test/ui/feature-gates/feature-gate-const_generics.rs
@@ -1,7 +1,5 @@
 fn foo<const X: ()>() {} //~ ERROR const generics are unstable
-//~^ const generics in any position are currently unsupported
 
 struct Foo<const X: usize>([(); X]); //~ ERROR const generics are unstable
-//~^ const generics in any position are currently unsupported
 
 fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-const_generics.stderr b/src/test/ui/feature-gates/feature-gate-const_generics.stderr
index 3ab1aa2367f..bd86a4197a7 100644
--- a/src/test/ui/feature-gates/feature-gate-const_generics.stderr
+++ b/src/test/ui/feature-gates/feature-gate-const_generics.stderr
@@ -7,25 +7,13 @@ LL | fn foo<const X: ()>() {} //~ ERROR const generics are unstable
    = help: add #![feature(const_generics)] to the crate attributes to enable
 
 error[E0658]: const generics are unstable (see issue #44580)
-  --> $DIR/feature-gate-const_generics.rs:4:18
+  --> $DIR/feature-gate-const_generics.rs:3:18
    |
 LL | struct Foo<const X: usize>([(); X]); //~ ERROR const generics are unstable
    |                  ^
    |
    = help: add #![feature(const_generics)] to the crate attributes to enable
 
-error: const generics in any position are currently unsupported
-  --> $DIR/feature-gate-const_generics.rs:1:14
-   |
-LL | fn foo<const X: ()>() {} //~ ERROR const generics are unstable
-   |              ^
-
-error: const generics in any position are currently unsupported
-  --> $DIR/feature-gate-const_generics.rs:4:18
-   |
-LL | struct Foo<const X: usize>([(); X]); //~ ERROR const generics are unstable
-   |                  ^
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0658`.