diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs
index b15bea017762e..f6d864f5b404d 100644
--- a/src/librustc/hir/def.rs
+++ b/src/librustc/hir/def.rs
@@ -52,13 +52,13 @@ pub enum Def {
     AssociatedExistential(DefId),
     PrimTy(hir::PrimTy),
     TyParam(DefId),
-    ConstParam(DefId),
     SelfTy(Option<DefId> /* trait */, Option<DefId> /* impl */),
     ToolMod, // e.g., `rustfmt` in `#[rustfmt::skip]`
 
     // Value namespace
     Fn(DefId),
     Const(DefId),
+    ConstParam(DefId),
     Static(DefId, bool /* is_mutbl */),
     StructCtor(DefId, CtorKind), // `DefId` refers to `NodeId` of the struct's constructor
     VariantCtor(DefId, CtorKind), // `DefId` refers to the enum variant
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 9436c600c9fd3..94b036fded5a1 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -334,6 +334,7 @@ pub trait Visitor<'v> : Sized {
         match generic_arg {
             GenericArg::Lifetime(lt) => self.visit_lifetime(lt),
             GenericArg::Type(ty) => self.visit_ty(ty),
+            GenericArg::Const(ct) => self.visit_anon_const(&ct.value),
         }
     }
     fn visit_lifetime(&mut self, lifetime: &'v Lifetime) {
@@ -752,6 +753,7 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Generi
     match param.kind {
         GenericParamKind::Lifetime { .. } => {}
         GenericParamKind::Type { ref default, .. } => walk_list!(visitor, visit_ty, default),
+        GenericParamKind::Const { ref ty } => visitor.visit_ty(ty),
     }
     walk_list!(visitor, visit_param_bound, &param.bounds);
 }
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 84487c40f8745..52c3eb26d6180 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -36,7 +36,7 @@ use crate::hir::HirVec;
 use crate::hir::map::{DefKey, DefPathData, Definitions};
 use crate::hir::def_id::{DefId, DefIndex, DefIndexAddressSpace, CRATE_DEF_INDEX};
 use crate::hir::def::{Def, PathResolution, PerNS};
-use crate::hir::GenericArg;
+use crate::hir::{GenericArg, ConstArg};
 use crate::lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
                     ELIDED_LIFETIMES_IN_PATHS};
 use crate::middle::cstore::CrateStore;
@@ -1172,13 +1172,10 @@ impl<'a> LoweringContext<'a> {
             ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(&lt)),
             ast::GenericArg::Type(ty) => GenericArg::Type(self.lower_ty_direct(&ty, itctx)),
             ast::GenericArg::Const(ct) => {
-                // FIXME(const_generics): const generics are not yet defined in the HIR.
-                self.sess.struct_span_err(
-                    ct.value.span,
-                    "const generics in any position are currently unsupported",
-                ).emit();
-                self.sess.abort_if_errors();
-                bug!();
+                GenericArg::Const(ConstArg {
+                    value: self.lower_anon_const(&ct),
+                    span: ct.value.span,
+                })
             }
         }
     }
@@ -2520,14 +2517,10 @@ impl<'a> LoweringContext<'a> {
 
                 (hir::ParamName::Plain(ident), kind)
             }
-            GenericParamKind::Const { .. } => {
-                // FIXME(const_generics): const generics are not yet defined in the HIR.
-                self.sess.struct_span_err(
-                    param.ident.span,
-                    "const generics in any position are currently unsupported",
-                ).emit();
-                self.sess.abort_if_errors();
-                bug!();
+            GenericParamKind::Const { ref ty } => {
+                (hir::ParamName::Plain(param.ident), hir::GenericParamKind::Const {
+                    ty: self.lower_ty(&ty, ImplTraitContext::disallowed()),
+                })
             }
         };
 
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index b6cf4c1b84d0c..e933e4b7180c4 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -398,6 +398,7 @@ impl<'hir> Map<'hir> {
                 Some(match param.kind {
                     GenericParamKind::Lifetime { .. } => Def::Local(param.id),
                     GenericParamKind::Type { .. } => Def::TyParam(self.local_def_id(param.id)),
+                    GenericParamKind::Const { .. } => Def::ConstParam(self.local_def_id(param.id)),
                 })
             }
         }
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index d774359fa79ec..d7d56ef659afb 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -389,10 +389,17 @@ impl PathSegment {
     }
 }
 
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+pub struct ConstArg {
+    pub value: AnonConst,
+    pub span: Span,
+}
+
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub enum GenericArg {
     Lifetime(Lifetime),
     Type(Ty),
+    Const(ConstArg),
 }
 
 impl GenericArg {
@@ -400,6 +407,7 @@ impl GenericArg {
         match self {
             GenericArg::Lifetime(l) => l.span,
             GenericArg::Type(t) => t.span,
+            GenericArg::Const(c) => c.span,
         }
     }
 
@@ -407,6 +415,7 @@ impl GenericArg {
         match self {
             GenericArg::Lifetime(l) => l.id,
             GenericArg::Type(t) => t.id,
+            GenericArg::Const(c) => c.value.id,
         }
     }
 }
@@ -448,6 +457,7 @@ impl GenericArgs {
                         }
                         break;
                     }
+                    GenericArg::Const(_) => {}
                 }
             }
         }
@@ -464,6 +474,7 @@ impl GenericArgs {
             match arg {
                 GenericArg::Lifetime(_) => own_counts.lifetimes += 1,
                 GenericArg::Type(_) => own_counts.types += 1,
+                GenericArg::Const(_) => own_counts.consts += 1,
             };
         }
 
@@ -528,6 +539,9 @@ pub enum GenericParamKind {
     Type {
         default: Option<P<Ty>>,
         synthetic: Option<SyntheticTyParamKind>,
+    },
+    Const {
+        ty: P<Ty>,
     }
 }
 
@@ -548,6 +562,7 @@ pub struct GenericParam {
 pub struct GenericParamCount {
     pub lifetimes: usize,
     pub types: usize,
+    pub consts: usize,
 }
 
 /// Represents lifetimes and type parameters attached to a declaration
@@ -582,6 +597,7 @@ impl Generics {
             match param.kind {
                 GenericParamKind::Lifetime { .. } => own_counts.lifetimes += 1,
                 GenericParamKind::Type { .. } => own_counts.types += 1,
+                GenericParamKind::Const { .. } => own_counts.consts += 1,
             };
         }
 
@@ -1302,7 +1318,7 @@ impl BodyOwnerKind {
 /// These are usually found nested inside types (e.g., array lengths)
 /// or expressions (e.g., repeat counts), and also used to define
 /// explicit discriminant values for enum variants.
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)]
 pub struct AnonConst {
     pub id: NodeId,
     pub hir_id: HirId,
diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs
index e2df290a455c4..312351ab850c2 100644
--- a/src/librustc/hir/pat_util.rs
+++ b/src/librustc/hir/pat_util.rs
@@ -64,19 +64,6 @@ impl hir::Pat {
         }
     }
 
-    pub fn is_const(&self) -> bool {
-        match self.node {
-            PatKind::Path(hir::QPath::TypeRelative(..)) => true,
-            PatKind::Path(hir::QPath::Resolved(_, ref path)) => {
-                match path.def {
-                    Def::Const(..) | Def::AssociatedConst(..) => true,
-                    _ => false
-                }
-            }
-            _ => false
-        }
-    }
-
     /// Call `f` on every "binding" in a pattern, e.g., on `a` in
     /// `match foo() { Some(a) => (), None => () }`
     pub fn each_binding<F>(&self, mut f: F)
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 9b6fcf259be14..031b3a3233d6f 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -1711,31 +1711,25 @@ impl<'a> State<'a> {
                 }
             };
 
-            let mut types = vec![];
-            let mut elide_lifetimes = true;
-            for arg in &generic_args.args {
-                match arg {
-                    GenericArg::Lifetime(lt) => {
-                        if !lt.is_elided() {
-                            elide_lifetimes = false;
-                        }
-                    }
-                    GenericArg::Type(ty) => {
-                        types.push(ty);
-                    }
+            let mut nonelided_generic_args: bool = false;
+            let elide_lifetimes = generic_args.args.iter().all(|arg| match arg {
+                GenericArg::Lifetime(lt) => lt.is_elided(),
+                _ => {
+                    nonelided_generic_args = true;
+                    true
                 }
-            }
-            if !elide_lifetimes {
+            });
+
+            if nonelided_generic_args {
                 start_or_comma(self)?;
                 self.commasep(Inconsistent, &generic_args.args, |s, generic_arg| {
                     match generic_arg {
-                        GenericArg::Lifetime(lt) => s.print_lifetime(lt),
+                        GenericArg::Lifetime(lt) if !elide_lifetimes => s.print_lifetime(lt),
+                        GenericArg::Lifetime(_) => Ok(()),
                         GenericArg::Type(ty) => s.print_type(ty),
+                        GenericArg::Const(ct) => s.print_anon_const(&ct.value),
                     }
                 })?;
-            } else if !types.is_empty() {
-                start_or_comma(self)?;
-                self.commasep(Inconsistent, &types, |s, ty| s.print_type(&ty))?;
             }
 
             // FIXME(eddyb) This would leak into error messages, e.g.:
@@ -2106,7 +2100,12 @@ impl<'a> State<'a> {
     }
 
     pub fn print_generic_param(&mut self, param: &GenericParam) -> io::Result<()> {
+        if let GenericParamKind::Const { .. } = param.kind {
+            self.word_space("const")?;
+        }
+
         self.print_ident(param.name.ident())?;
+
         match param.kind {
             GenericParamKind::Lifetime { .. } => {
                 let mut sep = ":";
@@ -2133,6 +2132,10 @@ impl<'a> State<'a> {
                     _ => Ok(()),
                 }
             }
+            GenericParamKind::Const { ref ty } => {
+                self.word_space(":")?;
+                self.print_type(ty)
+            }
         }
     }
 
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
index b10e893732597..727c441b0e8db 100644
--- a/src/librustc/ich/impls_hir.rs
+++ b/src/librustc/ich/impls_hir.rs
@@ -179,9 +179,15 @@ impl_stable_hash_for!(struct hir::PathSegment {
     args
 });
 
+impl_stable_hash_for!(struct hir::ConstArg {
+    value,
+    span,
+});
+
 impl_stable_hash_for!(enum hir::GenericArg {
     Lifetime(lt),
-    Type(ty)
+    Type(ty),
+    Const(ct),
 });
 
 impl_stable_hash_for!(struct hir::GenericArgs {
@@ -231,6 +237,9 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::GenericParamKind {
                 default.hash_stable(hcx, hasher);
                 synthetic.hash_stable(hcx, hasher);
             }
+            hir::GenericParamKind::Const { ref ty } => {
+                ty.hash_stable(hcx, hasher);
+            }
         }
     }
 }
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 231dcc9bfd272..56e7d78935698 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -704,7 +704,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
                hir_id, expr_ty, def);
 
         match def {
-            Def::StructCtor(..) | Def::VariantCtor(..) | Def::Const(..) |
+            Def::StructCtor(..) | Def::VariantCtor(..) | Def::Const(..) | Def::ConstParam(..) |
             Def::AssociatedConst(..) | Def::Fn(..) | Def::Method(..) | Def::SelfCtor(..) => {
                 Ok(self.cat_rvalue_node(hir_id, span, expr_ty))
             }
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index 99d0c5e88d638..0562fddb2b523 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -315,8 +315,11 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
             Node::Ty(_) |
             Node::MacroDef(_) => {}
             _ => {
-                bug!("found unexpected thingy in worklist: {}",
-                     self.tcx.hir().node_to_string(search_item))
+                bug!(
+                    "found unexpected node kind in worklist: {} ({:?})",
+                    self.tcx.hir().node_to_string(search_item),
+                    node,
+                );
             }
         }
     }
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 5f7b9cc33660f..08da74f47d450 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -527,23 +527,20 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 } else {
                     0
                 };
-                let mut type_count = 0;
-                let lifetimes = generics
-                    .params
-                    .iter()
-                    .filter_map(|param| match param.kind {
-                        GenericParamKind::Lifetime { .. } => {
-                            Some(Region::early(&self.tcx.hir(), &mut index, param))
-                        }
-                        GenericParamKind::Type { .. } => {
-                            type_count += 1;
-                            None
-                        }
-                    })
-                    .collect();
+                let mut non_lifetime_count = 0;
+                let lifetimes = generics.params.iter().filter_map(|param| match param.kind {
+                    GenericParamKind::Lifetime { .. } => {
+                        Some(Region::early(&self.tcx.hir(), &mut index, param))
+                    }
+                    GenericParamKind::Type { .. } |
+                    GenericParamKind::Const { .. } => {
+                        non_lifetime_count += 1;
+                        None
+                    }
+                }).collect();
                 let scope = Scope::Binder {
                     lifetimes,
-                    next_early_index: index + type_count,
+                    next_early_index: index + non_lifetime_count,
                     abstract_type_parent: true,
                     track_lifetime_uses,
                     s: ROOT_SCOPE,
@@ -708,7 +705,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
 
                 let mut elision = None;
                 let mut lifetimes = FxHashMap::default();
-                let mut type_count = 0;
+                let mut non_lifetime_count = 0;
                 for param in &generics.params {
                     match param.kind {
                         GenericParamKind::Lifetime { .. } => {
@@ -725,12 +722,13 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                                 lifetimes.insert(name, reg);
                             }
                         }
-                        GenericParamKind::Type { .. } => {
-                            type_count += 1;
+                        GenericParamKind::Type { .. } |
+                        GenericParamKind::Const { .. } => {
+                            non_lifetime_count += 1;
                         }
                     }
                 }
-                let next_early_index = index + type_count;
+                let next_early_index = index + non_lifetime_count;
 
                 if let Some(elision_region) = elision {
                     let scope = Scope::Elision {
@@ -788,23 +786,20 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 let generics = &trait_item.generics;
                 let mut index = self.next_early_index();
                 debug!("visit_ty: index = {}", index);
-                let mut type_count = 0;
-                let lifetimes = generics
-                    .params
-                    .iter()
-                    .filter_map(|param| match param.kind {
-                        GenericParamKind::Lifetime { .. } => {
-                            Some(Region::early(&self.tcx.hir(), &mut index, param))
-                        }
-                        GenericParamKind::Type { .. } => {
-                            type_count += 1;
-                            None
-                        }
-                    })
-                    .collect();
+                let mut non_lifetime_count = 0;
+                let lifetimes = generics.params.iter().filter_map(|param| match param.kind {
+                    GenericParamKind::Lifetime { .. } => {
+                        Some(Region::early(&self.tcx.hir(), &mut index, param))
+                    }
+                    GenericParamKind::Type { .. } |
+                    GenericParamKind::Const { .. } => {
+                        non_lifetime_count += 1;
+                        None
+                    }
+                }).collect();
                 let scope = Scope::Binder {
                     lifetimes,
-                    next_early_index: index + type_count,
+                    next_early_index: index + non_lifetime_count,
                     s: self.scope,
                     track_lifetime_uses: true,
                     abstract_type_parent: true,
@@ -842,24 +837,21 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
             Type(ref ty) => {
                 let generics = &impl_item.generics;
                 let mut index = self.next_early_index();
-                let mut next_early_index = index;
+                let mut non_lifetime_count = 0;
                 debug!("visit_ty: index = {}", index);
-                let lifetimes = generics
-                    .params
-                    .iter()
-                    .filter_map(|param| match param.kind {
-                        GenericParamKind::Lifetime { .. } => {
-                            Some(Region::early(&self.tcx.hir(), &mut index, param))
-                        }
-                        GenericParamKind::Type { .. } => {
-                            next_early_index += 1;
-                            None
-                        }
-                    })
-                    .collect();
+                let lifetimes = generics.params.iter().filter_map(|param| match param.kind {
+                    GenericParamKind::Lifetime { .. } => {
+                        Some(Region::early(&self.tcx.hir(), &mut index, param))
+                    }
+                    GenericParamKind::Const { .. } |
+                    GenericParamKind::Type { .. } => {
+                        non_lifetime_count += 1;
+                        None
+                    }
+                }).collect();
                 let scope = Scope::Binder {
                     lifetimes,
-                    next_early_index,
+                    next_early_index: index + non_lifetime_count,
                     s: self.scope,
                     track_lifetime_uses: true,
                     abstract_type_parent: true,
@@ -874,19 +866,19 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 let mut index = self.next_early_index();
                 let mut next_early_index = index;
                 debug!("visit_ty: index = {}", index);
-                let lifetimes = generics
-                    .params
-                    .iter()
-                    .filter_map(|param| match param.kind {
-                        GenericParamKind::Lifetime { .. } => {
-                            Some(Region::early(&self.tcx.hir(), &mut index, param))
-                        }
-                        GenericParamKind::Type { .. } => {
-                            next_early_index += 1;
-                            None
-                        }
-                    })
-                    .collect();
+                let lifetimes = generics.params.iter().filter_map(|param| match param.kind {
+                    GenericParamKind::Lifetime { .. } => {
+                        Some(Region::early(&self.tcx.hir(), &mut index, param))
+                    }
+                    GenericParamKind::Type { .. } => {
+                        next_early_index += 1;
+                        None
+                    }
+                    GenericParamKind::Const { .. } => {
+                        next_early_index += 1;
+                        None
+                    }
+                }).collect();
 
                 let scope = Scope::Binder {
                     lifetimes,
@@ -950,6 +942,10 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                         self.visit_ty(&ty);
                     }
                 }
+                GenericParamKind::Const { ref ty, .. } => {
+                    walk_list!(self, visit_param_bound, &param.bounds);
+                    self.visit_ty(&ty);
+                }
             }
         }
         for predicate in &generics.where_clause.predicates {
@@ -1395,6 +1391,10 @@ fn object_lifetime_defaults_for_item(
                     Set1::Many => Set1::Many,
                 })
             }
+            GenericParamKind::Const { .. } => {
+                // Generic consts don't impose any constraints.
+                None
+            }
         })
         .collect()
 }
@@ -1703,25 +1703,22 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             }
         }
 
-        let mut type_count = 0;
-        let lifetimes = generics
-            .params
-            .iter()
-            .filter_map(|param| match param.kind {
-                GenericParamKind::Lifetime { .. } => {
-                    if self.map.late_bound.contains(&param.id) {
-                        Some(Region::late(&self.tcx.hir(), param))
-                    } else {
-                        Some(Region::early(&self.tcx.hir(), &mut index, param))
-                    }
-                }
-                GenericParamKind::Type { .. } => {
-                    type_count += 1;
-                    None
+        let mut non_lifetime_count = 0;
+        let lifetimes = generics.params.iter().filter_map(|param| match param.kind {
+            GenericParamKind::Lifetime { .. } => {
+                if self.map.late_bound.contains(&param.id) {
+                    Some(Region::late(&self.tcx.hir(), param))
+                } else {
+                    Some(Region::early(&self.tcx.hir(), &mut index, param))
                 }
-            })
-            .collect();
-        let next_early_index = index + type_count;
+            }
+            GenericParamKind::Type { .. } |
+            GenericParamKind::Const { .. } => {
+                non_lifetime_count += 1;
+                None
+            }
+        }).collect();
+        let next_early_index = index + non_lifetime_count;
 
         let scope = Scope::Binder {
             lifetimes,
@@ -2011,6 +2008,9 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                     }
                     i += 1;
                 }
+                GenericArg::Const(ct) => {
+                    self.visit_anon_const(&ct.value);
+                }
             }
         }
 
@@ -2768,8 +2768,9 @@ fn insert_late_bound_lifetimes(
         match param.kind {
             hir::GenericParamKind::Lifetime { .. } => { /* fall through */ }
 
-            // Types are not late-bound.
-            hir::GenericParamKind::Type { .. } => continue,
+            // Neither types nor consts are late-bound.
+            hir::GenericParamKind::Type { .. }
+            | hir::GenericParamKind::Const { .. } => continue,
         }
 
         let lt_name = hir::LifetimeName::Param(param.name.modern());
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 28e01bd9793fd..925cde5b5cc8b 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -907,11 +907,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidNoMangleItems {
                     for param in &generics.params {
                         match param.kind {
                             GenericParamKind::Lifetime { .. } => {}
-                            GenericParamKind::Type { .. } => {
-                                let mut err = cx.struct_span_lint(NO_MANGLE_GENERIC_ITEMS,
-                                                                  it.span,
-                                                                  "functions generic over \
-                                                                   types must be mangled");
+                            GenericParamKind::Type { .. } |
+                            GenericParamKind::Const { .. } => {
+                                let mut err = cx.struct_span_lint(
+                                    NO_MANGLE_GENERIC_ITEMS,
+                                    it.span,
+                                    "functions generic over types or consts must be mangled",
+                                );
                                 err.span_suggestion_short(
                                     no_mangle_attr.span,
                                     "remove this attribute",
@@ -1791,14 +1793,15 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExplicitOutlivesRequirements {
 
             for param in &generics.params {
                 let param_name = match param.kind {
-                    hir::GenericParamKind::Lifetime { .. } => { continue; },
+                    hir::GenericParamKind::Lifetime { .. } => continue,
                     hir::GenericParamKind::Type { .. } => {
                         match param.name {
-                            hir::ParamName::Fresh(_) => { continue; },
-                            hir::ParamName::Error => { continue; },
-                            hir::ParamName::Plain(name) => name.to_string()
+                            hir::ParamName::Fresh(_) => continue,
+                            hir::ParamName::Error => continue,
+                            hir::ParamName::Plain(name) => name.to_string(),
                         }
                     }
+                    hir::GenericParamKind::Const { .. } => continue,
                 };
                 let bound_spans = self.collect_outlives_bound_spans(
                     cx, def_id, &param_name, &param.bounds, infer_static
diff --git a/src/librustc_lint/nonstandard_style.rs b/src/librustc_lint/nonstandard_style.rs
index c2dd9a3d1b84f..7c66289703ac8 100644
--- a/src/librustc_lint/nonstandard_style.rs
+++ b/src/librustc_lint/nonstandard_style.rs
@@ -455,6 +455,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonUpperCaseGlobals {
             }
         }
     }
+
+    fn check_generic_param(&mut self, cx: &LateContext<'_, '_>, param: &hir::GenericParam) {
+        if let GenericParamKind::Const { .. } = param.kind {
+            NonUpperCaseGlobals::check_upper_case(
+                cx,
+                "const parameter",
+                &param.name.ident(),
+            );
+        }
+    }
 }
 
 #[cfg(test)]
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 40d3ee9cc0b11..776adc077fc08 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -1331,6 +1331,29 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
         }
     }
 
+    fn encode_info_for_const_param(&mut self, def_id: DefId) -> Entry<'tcx> {
+        debug!("IsolatedEncoder::encode_info_for_const_param({:?})", def_id);
+        let tcx = self.tcx;
+        Entry {
+            kind: EntryKind::Type,
+            visibility: self.lazy(&ty::Visibility::Public),
+            span: self.lazy(&tcx.def_span(def_id)),
+            attributes: LazySeq::empty(),
+            children: LazySeq::empty(),
+            stability: None,
+            deprecation: None,
+
+            ty: Some(self.encode_item_type(def_id)),
+            inherent_impls: LazySeq::empty(),
+            variances: LazySeq::empty(),
+            generics: None,
+            predicates: None,
+            predicates_defined_on: None,
+
+            mir: None,
+        }
+    }
+
     fn encode_info_for_closure(&mut self, def_id: DefId) -> Entry<'tcx> {
         debug!("IsolatedEncoder::encode_info_for_closure({:?})", def_id);
         let tcx = self.tcx;
@@ -1684,6 +1707,11 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
                     let encode_info = IsolatedEncoder::encode_info_for_ty_param;
                     self.record(def_id, encode_info, (def_id, has_default));
                 }
+                hir::GenericParamKind::Const { .. } => {
+                    let def_id = self.tcx.hir().local_def_id(param.id);
+                    let encode_info = IsolatedEncoder::encode_info_for_const_param;
+                    self.record(def_id, encode_info, def_id);
+                }
             }
         }
     }
diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs
index a76aa7454cbe4..e68702bfe3ae0 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -1090,7 +1090,10 @@ fn create_mono_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             for param in &generics.params {
                 match param.kind {
                     hir::GenericParamKind::Lifetime { .. } => {}
-                    hir::GenericParamKind::Type { .. } => return,
+                    hir::GenericParamKind::Type { .. } |
+                    hir::GenericParamKind::Const { .. } => {
+                        return
+                    }
                 }
             }
 
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 23e9cd55cdce7..cde6eb22bb8ae 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -500,19 +500,20 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                                 args.next();
                                 params.next();
                             }
-                            (GenericArg::Lifetime(_), GenericParamDefKind::Type { .. }) => {
-                                // We expected a type argument, but got a lifetime
-                                // argument. This is an error, but we need to handle it
-                                // gracefully so we can report sensible errors. In this
-                                // case, we're simply going to infer this argument.
-                                args.next();
-                            }
-                            (GenericArg::Type(_), GenericParamDefKind::Lifetime) => {
-                                // We expected a lifetime argument, but got a type
+                            (GenericArg::Type(_), GenericParamDefKind::Lifetime)
+                            | (GenericArg::Const(_), GenericParamDefKind::Lifetime) => {
+                                // We expected a lifetime argument, but got a type or const
                                 // argument. That means we're inferring the lifetimes.
                                 substs.push(inferred_kind(None, param, infer_types));
                                 params.next();
                             }
+                            (_, _) => {
+                                // We expected one kind of parameter, but the user provided
+                                // another. This is an error, but we need to handle it
+                                // gracefully so we can report sensible errors.
+                                // In this case, we're simply going to infer this argument.
+                                args.next();
+                            }
                         }
                     }
                     (Some(_), None) => {
@@ -524,12 +525,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                     (None, Some(&param)) => {
                         // If there are fewer arguments than parameters, it means
                         // we're inferring the remaining arguments.
-                        match param.kind {
-                            GenericParamDefKind::Lifetime | GenericParamDefKind::Type { .. } => {
-                                let kind = inferred_kind(Some(&substs), param, infer_types);
-                                substs.push(kind);
-                            }
-                        }
+                        substs.push(inferred_kind(Some(&substs), param, infer_types));
                         args.next();
                         params.next();
                     }
@@ -1459,9 +1455,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
         let mut has_err = false;
         for segment in segments {
             segment.with_generic_args(|generic_args| {
-                let (mut err_for_lt, mut err_for_ty) = (false, false);
+                let (mut err_for_lt, mut err_for_ty, mut err_for_ct) = (false, false, false);
                 for arg in &generic_args.args {
                     let (mut span_err, span, kind) = match arg {
+                        // FIXME(varkor): unify E0109, E0110 and E0111.
                         hir::GenericArg::Lifetime(lt) => {
                             if err_for_lt { continue }
                             err_for_lt = true;
@@ -1480,10 +1477,18 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
                              ty.span,
                              "type")
                         }
+                        hir::GenericArg::Const(ct) => {
+                            if err_for_ct { continue }
+                            err_for_ct = true;
+                            (struct_span_err!(self.tcx().sess, ct.span, E0111,
+                                              "const parameters are not allowed on this type"),
+                             ct.span,
+                             "const")
+                        }
                     };
                     span_err.span_label(span, format!("{} argument not allowed", kind))
                             .emit();
-                    if err_for_lt && err_for_ty {
+                    if err_for_lt && err_for_ty && err_for_ct {
                         break;
                     }
                 }
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index 05ca54df2984b..5f1c2efb6a457 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -840,7 +840,8 @@ fn compare_synthetic_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                         let bounds = impl_m.generics.params.iter().find_map(|param| {
                             match param.kind {
                                 GenericParamKind::Lifetime { .. } => None,
-                                GenericParamKind::Type { .. } => {
+                                GenericParamKind::Type { .. } |
+                                GenericParamKind::Const { .. } => {
                                     if param.hir_id == impl_hir_id {
                                         Some(&param.bounds)
                                     } else {
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 4a2d526263c03..84de38beafad9 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -132,6 +132,10 @@ impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> {
                     self.tcx.type_of(def_id);
                 }
                 hir::GenericParamKind::Type { .. } => {}
+                hir::GenericParamKind::Const { .. } => {
+                    let def_id = self.tcx.hir().local_def_id(param.id);
+                    self.tcx.type_of(def_id);
+                }
             }
         }
         intravisit::walk_generics(self, generics);
@@ -1041,6 +1045,22 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty
                     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",
+                        );
+                    }
+
+                    // 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,
             }),
     );
@@ -1301,10 +1321,10 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> {
         },
 
         Node::GenericParam(param) => match &param.kind {
-            hir::GenericParamKind::Type {
-                default: Some(ref ty),
-                ..
-            } => icx.to_ty(ty),
+            hir::GenericParamKind::Type { default: Some(ref ty), .. } |
+            hir::GenericParamKind::Const { ref ty, .. } => {
+                icx.to_ty(ty)
+            }
             x => bug!("unexpected non-type Node::GenericParam: {:?}", x),
         },
 
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index 71767fcfd4933..3c4a0760f3ee2 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -1326,6 +1326,10 @@ type X = u32; // ok!
 ```
 "##,
 
+E0111: r##"
+You tried to give a const parameter to a type which doesn't need it.
+"##,
+
 E0116: r##"
 You can only define an inherent implementation for a type in the same crate
 where the type was defined. For example, an `impl` block as below is not allowed
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index b99181c0d4f9e..8796cfa01e0ea 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -773,6 +773,7 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> {
                     }
                 }
                 GenericParamDefKind::Lifetime => {}
+                GenericParamDefKind::Const { .. } => {}
             }
         }
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index d12b5021ca9fa..92afbc56c557b 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1253,6 +1253,15 @@ impl Clean<Lifetime> for hir::GenericParam {
     }
 }
 
+impl Clean<Constant> for hir::ConstArg {
+    fn clean(&self, cx: &DocContext) -> Constant {
+        Constant {
+            type_: cx.tcx.type_of(cx.tcx.hir().body_owner_def_id(self.value.body)).clean(cx),
+            expr: print_const_expr(cx, self.value.body),
+        }
+    }
+}
+
 impl<'tcx> Clean<Lifetime> for ty::GenericParamDef {
     fn clean(&self, _cx: &DocContext) -> Lifetime {
         Lifetime(self.name.to_string())
@@ -1418,6 +1427,10 @@ pub enum GenericParamDefKind {
         default: Option<Type>,
         synthetic: Option<hir::SyntheticTyParamKind>,
     },
+    Const {
+        did: DefId,
+        ty: Type,
+    },
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
@@ -1430,7 +1443,10 @@ pub struct GenericParamDef {
 impl GenericParamDef {
     pub fn is_synthetic_type_param(&self) -> bool {
         match self.kind {
-            GenericParamDefKind::Lifetime => false,
+            GenericParamDefKind::Lifetime |
+            GenericParamDefKind::Const { .. } => {
+                false
+            }
             GenericParamDefKind::Type { ref synthetic, .. } => synthetic.is_some(),
         }
     }
@@ -1486,7 +1502,7 @@ impl Clean<GenericParamDef> for hir::GenericParam {
                 };
                 (name, GenericParamDefKind::Lifetime)
             }
-            hir::GenericParamKind::Type { ref default, synthetic, .. } => {
+            hir::GenericParamKind::Type { ref default, synthetic } => {
                 (self.name.ident().name.clean(cx), GenericParamDefKind::Type {
                     did: cx.tcx.hir().local_def_id(self.id),
                     bounds: self.bounds.clean(cx),
@@ -1494,6 +1510,12 @@ impl Clean<GenericParamDef> for hir::GenericParam {
                     synthetic: synthetic,
                 })
             }
+            hir::GenericParamKind::Const { ref ty } => {
+                (self.name.ident().name.clean(cx), GenericParamDefKind::Const {
+                    did: cx.tcx.hir().local_def_id(self.id),
+                    ty: ty.clean(cx),
+                })
+            }
         };
 
         GenericParamDef {
@@ -1533,6 +1555,7 @@ impl Clean<Generics> for hir::Generics {
                     GenericParamDefKind::Type { did, ref bounds, .. } => {
                         cx.impl_trait_bounds.borrow_mut().insert(did, bounds.clone());
                     }
+                    GenericParamDefKind::Const { .. } => unreachable!(),
                 }
                 param
             })
@@ -1566,6 +1589,7 @@ impl Clean<Generics> for hir::Generics {
                                         break
                                     }
                                 }
+                                GenericParamDefKind::Const { .. } => {}
                             }
                         }
                     }
@@ -2544,6 +2568,7 @@ impl Clean<Type> for hir::Ty {
                     let provided_params = &path.segments.last().expect("segments were empty");
                     let mut ty_substs = FxHashMap::default();
                     let mut lt_substs = FxHashMap::default();
+                    let mut const_substs = FxHashMap::default();
                     provided_params.with_generic_args(|generic_args| {
                         let mut indices: GenericParamCount = Default::default();
                         for param in generics.params.iter() {
@@ -2552,7 +2577,7 @@ impl Clean<Type> for hir::Ty {
                                     let mut j = 0;
                                     let lifetime = generic_args.args.iter().find_map(|arg| {
                                         match arg {
-                                            GenericArg::Lifetime(lt) => {
+                                            hir::GenericArg::Lifetime(lt) => {
                                                 if indices.lifetimes == j {
                                                     return Some(lt);
                                                 }
@@ -2577,7 +2602,7 @@ impl Clean<Type> for hir::Ty {
                                     let mut j = 0;
                                     let type_ = generic_args.args.iter().find_map(|arg| {
                                         match arg {
-                                            GenericArg::Type(ty) => {
+                                            hir::GenericArg::Type(ty) => {
                                                 if indices.types == j {
                                                     return Some(ty);
                                                 }
@@ -2595,10 +2620,32 @@ impl Clean<Type> for hir::Ty {
                                     }
                                     indices.types += 1;
                                 }
+                                hir::GenericParamKind::Const { .. } => {
+                                    let const_param_def =
+                                        Def::ConstParam(cx.tcx.hir().local_def_id(param.id));
+                                    let mut j = 0;
+                                    let const_ = generic_args.args.iter().find_map(|arg| {
+                                        match arg {
+                                            hir::GenericArg::Const(ct) => {
+                                                if indices.consts == j {
+                                                    return Some(ct);
+                                                }
+                                                j += 1;
+                                                None
+                                            }
+                                            _ => None,
+                                        }
+                                    });
+                                    if let Some(ct) = const_.cloned() {
+                                        const_substs.insert(const_param_def, ct.clean(cx));
+                                    }
+                                    // FIXME(const_generics:defaults)
+                                    indices.consts += 1;
+                                }
                             }
                         }
                     });
-                    return cx.enter_alias(ty_substs, lt_substs, || ty.clean(cx));
+                    return cx.enter_alias(ty_substs, lt_substs, const_substs, || ty.clean(cx));
                 }
                 resolve_type(cx, path.clean(cx), self.id)
             }
@@ -3190,6 +3237,9 @@ impl Clean<GenericArgs> for hir::GenericArgs {
                     GenericArg::Type(ty) => {
                         types.push(ty.clean(cx));
                     }
+                    GenericArg::Const(..) => {
+                        unimplemented!() // FIXME(const_generics)
+                    }
                 }
             }
             GenericArgs::AngleBracketed {
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index e90127ca162d2..59820e4e5d1ae 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -65,6 +65,8 @@ pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a> {
     pub ty_substs: RefCell<FxHashMap<Def, clean::Type>>,
     /// Table `NodeId` of lifetime parameter definition -> substituted lifetime
     pub lt_substs: RefCell<FxHashMap<DefId, clean::Lifetime>>,
+    /// Table node id of const parameter definition -> substituted const
+    pub ct_substs: RefCell<FxHashMap<Def, clean::Constant>>,
     /// Table DefId of `impl Trait` in argument position -> bounds
     pub impl_trait_bounds: RefCell<FxHashMap<DefId, Vec<clean::GenericBound>>>,
     pub send_trait: Option<DefId>,
@@ -85,14 +87,18 @@ impl<'a, 'tcx, 'rcx> DocContext<'a, 'tcx, 'rcx> {
     pub fn enter_alias<F, R>(&self,
                              ty_substs: FxHashMap<Def, clean::Type>,
                              lt_substs: FxHashMap<DefId, clean::Lifetime>,
+                             ct_substs: FxHashMap<Def, clean::Constant>,
                              f: F) -> R
     where F: FnOnce() -> R {
-        let (old_tys, old_lts) =
-            (mem::replace(&mut *self.ty_substs.borrow_mut(), ty_substs),
-             mem::replace(&mut *self.lt_substs.borrow_mut(), lt_substs));
+        let (old_tys, old_lts, old_cts) = (
+            mem::replace(&mut *self.ty_substs.borrow_mut(), ty_substs),
+            mem::replace(&mut *self.lt_substs.borrow_mut(), lt_substs),
+            mem::replace(&mut *self.ct_substs.borrow_mut(), ct_substs),
+        );
         let r = f();
         *self.ty_substs.borrow_mut() = old_tys;
         *self.lt_substs.borrow_mut() = old_lts;
+        *self.ct_substs.borrow_mut() = old_cts;
         r
     }
 
@@ -212,7 +218,7 @@ impl<'a, 'tcx, 'rcx> DocContext<'a, 'tcx, 'rcx> {
                         name: hir::LifetimeName::Param(name),
                     }));
                 }
-                ty::GenericParamDefKind::Type {..} => {
+                ty::GenericParamDefKind::Type { .. } => {
                     args.push(hir::GenericArg::Type(self.ty_param_to_ty(param.clone())));
                 }
             }
@@ -527,6 +533,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
                 renderinfo: RefCell::new(renderinfo),
                 ty_substs: Default::default(),
                 lt_substs: Default::default(),
+                ct_substs: Default::default(),
                 impl_trait_bounds: Default::default(),
                 send_trait: send_trait,
                 fake_def_ids: Default::default(),
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 35555f61bd150..4fbbaf0f2e183 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -138,6 +138,16 @@ impl fmt::Display for clean::GenericParamDef {
 
                 Ok(())
             }
+            clean::GenericParamDefKind::Const { ref ty, .. } => {
+                f.write_str("const ")?;
+                f.write_str(&self.name)?;
+
+                if f.alternate() {
+                    write!(f, ": {:#}", ty)
+                } else {
+                    write!(f, ":&nbsp;{}", ty)
+                }
+            }
         }
     }
 }
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index e660d27d74b4c..bf0757902fe0e 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -1746,7 +1746,8 @@ impl<'a> Cache {
         for param in &generics.params {
             match param.kind {
                 clean::GenericParamDefKind::Lifetime => {}
-                clean::GenericParamDefKind::Type { did, .. } => {
+                clean::GenericParamDefKind::Type { did, .. } |
+                clean::GenericParamDefKind::Const { did, .. } => {
                     self.typarams.insert(did, param.name.clone());
                 }
             }
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 3f120cbc4d337..47f826789e03e 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
@@ -8,6 +8,7 @@ fn foo<const X: (), T>(_: T) {
 
 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 aedcaf52e2688..a43415d0e5a43 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
@@ -22,5 +22,11 @@ error: const generics in any position are currently unsupported
 LL | fn foo<const X: (), T>(_: T) {
    |              ^
 
-error: aborting due to 3 previous errors
+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
 
diff --git a/src/test/ui/const-generics/const-parameter-uppercase-lint.rs b/src/test/ui/const-generics/const-parameter-uppercase-lint.rs
new file mode 100644
index 0000000000000..37fe9af98b3df
--- /dev/null
+++ b/src/test/ui/const-generics/const-parameter-uppercase-lint.rs
@@ -0,0 +1,8 @@
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+
+#![deny(non_upper_case_globals)]
+
+fn noop<const x: u32>() {
+    //~^ ERROR const generics in any position are currently unsupported
+}
diff --git a/src/test/ui/const-generics/const-parameter-uppercase-lint.stderr b/src/test/ui/const-generics/const-parameter-uppercase-lint.stderr
new file mode 100644
index 0000000000000..9683e91cef30c
--- /dev/null
+++ b/src/test/ui/const-generics/const-parameter-uppercase-lint.stderr
@@ -0,0 +1,19 @@
+warning: the feature `const_generics` is incomplete and may cause the compiler to crash
+  --> $DIR/const-parameter-uppercase-lint.rs:1:12
+   |
+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
+  --> $DIR/const-parameter-uppercase-lint.rs:6:15
+   |
+LL | fn noop<const x: u32>() {
+   |               ^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0601`.
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 a8a4ed5772299..907e00b11e556 100644
--- a/src/test/ui/feature-gates/feature-gate-const_generics.rs
+++ b/src/test/ui/feature-gates/feature-gate-const_generics.rs
@@ -2,5 +2,6 @@ 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 905cc07b6a175..3ab1aa2367f1c 100644
--- a/src/test/ui/feature-gates/feature-gate-const_generics.stderr
+++ b/src/test/ui/feature-gates/feature-gate-const_generics.stderr
@@ -20,6 +20,12 @@ error: const generics in any position are currently unsupported
 LL | fn foo<const X: ()>() {} //~ ERROR const generics are unstable
    |              ^
 
-error: aborting due to 3 previous errors
+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
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/generic/generic-no-mangle.rs b/src/test/ui/generic/generic-no-mangle.rs
index 15e662a41de22..994aebc7f6e3e 100644
--- a/src/test/ui/generic/generic-no-mangle.rs
+++ b/src/test/ui/generic/generic-no-mangle.rs
@@ -1,10 +1,10 @@
 #![deny(no_mangle_generic_items)]
 
 #[no_mangle]
-pub fn foo<T>() {} //~ ERROR functions generic over types must be mangled
+pub fn foo<T>() {} //~ ERROR functions generic over types or consts must be mangled
 
 #[no_mangle]
-pub extern fn bar<T>() {} //~ ERROR functions generic over types must be mangled
+pub extern fn bar<T>() {} //~ ERROR functions generic over types or consts must be mangled
 
 #[no_mangle]
 pub fn baz(x: &i32) -> &i32 { x }
diff --git a/src/test/ui/generic/generic-no-mangle.stderr b/src/test/ui/generic/generic-no-mangle.stderr
index 639ee19910155..3da39f1dc17cb 100644
--- a/src/test/ui/generic/generic-no-mangle.stderr
+++ b/src/test/ui/generic/generic-no-mangle.stderr
@@ -1,9 +1,9 @@
-error: functions generic over types must be mangled
+error: functions generic over types or consts must be mangled
   --> $DIR/generic-no-mangle.rs:4:1
    |
 LL | #[no_mangle]
    | ------------ help: remove this attribute
-LL | pub fn foo<T>() {} //~ ERROR functions generic over types must be mangled
+LL | pub fn foo<T>() {} //~ ERROR functions generic over types or consts must be mangled
    | ^^^^^^^^^^^^^^^^^^
    |
 note: lint level defined here
@@ -12,12 +12,12 @@ note: lint level defined here
 LL | #![deny(no_mangle_generic_items)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^
 
-error: functions generic over types must be mangled
+error: functions generic over types or consts must be mangled
   --> $DIR/generic-no-mangle.rs:7:1
    |
 LL | #[no_mangle]
    | ------------ help: remove this attribute
-LL | pub extern fn bar<T>() {} //~ ERROR functions generic over types must be mangled
+LL | pub extern fn bar<T>() {} //~ ERROR functions generic over types or consts must be mangled
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
diff --git a/src/test/ui/lint/suggestions.rs b/src/test/ui/lint/suggestions.rs
index a497953d73a05..67bd6dd501bd8 100644
--- a/src/test/ui/lint/suggestions.rs
+++ b/src/test/ui/lint/suggestions.rs
@@ -10,7 +10,7 @@
 #[no_mangle]
 //~^ HELP remove this attribute
 pub fn defiant<T>(_t: T) {}
-//~^ WARN functions generic over types must be mangled
+//~^ WARN functions generic over types or consts must be mangled
 
 #[no_mangle]
 fn rio_grande() {}
@@ -23,7 +23,7 @@ mod badlands {
     //~^ ERROR const items should never be #[no_mangle]
     //~| HELP try a static value
     #[no_mangle] pub fn val_jean<T>() {}
-    //~^ WARN functions generic over types must be mangled
+    //~^ WARN functions generic over types or consts must be mangled
     //~| HELP remove this attribute
 
     // ... but we can suggest just-`pub` instead of restricted
@@ -31,7 +31,7 @@ mod badlands {
     //~^ ERROR const items should never be #[no_mangle]
     //~| HELP try a static value
     #[no_mangle] pub(crate) fn crossfield<T>() {}
-    //~^ WARN functions generic over types must be mangled
+    //~^ WARN functions generic over types or consts must be mangled
     //~| HELP remove this attribute
 }
 
diff --git a/src/test/ui/lint/suggestions.stderr b/src/test/ui/lint/suggestions.stderr
index c70f17f95d028..1e4eabc9db0f7 100644
--- a/src/test/ui/lint/suggestions.stderr
+++ b/src/test/ui/lint/suggestions.stderr
@@ -54,7 +54,7 @@ LL | #[no_mangle] const DISCOVERY: usize = 1;
    |
    = note: #[deny(no_mangle_const_items)] on by default
 
-warning: functions generic over types must be mangled
+warning: functions generic over types or consts must be mangled
   --> $DIR/suggestions.rs:12:1
    |
 LL | #[no_mangle]
@@ -73,7 +73,7 @@ LL |     #[no_mangle] pub const DAUNTLESS: bool = true;
    |                  |
    |                  help: try a static value: `pub static`
 
-warning: functions generic over types must be mangled
+warning: functions generic over types or consts must be mangled
   --> $DIR/suggestions.rs:25:18
    |
 LL |     #[no_mangle] pub fn val_jean<T>() {}
@@ -89,7 +89,7 @@ LL |     #[no_mangle] pub(crate) const VETAR: bool = true;
    |                  |
    |                  help: try a static value: `pub static`
 
-warning: functions generic over types must be mangled
+warning: functions generic over types or consts must be mangled
   --> $DIR/suggestions.rs:33:18
    |
 LL |     #[no_mangle] pub(crate) fn crossfield<T>() {}