diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index b32fa2cda8012..61d63f4623249 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -59,7 +59,7 @@ use crate::traits::query::{
     CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
     CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal,
 };
-use crate::ty::subst::SubstsRef;
+use crate::ty::subst::{GenericArg, SubstsRef};
 use crate::ty::{self, ParamEnvAnd, Ty, TyCtxt};
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs
index 54f5103f736ec..1cc5c6e6f4ae7 100644
--- a/src/librustc/query/mod.rs
+++ b/src/librustc/query/mod.rs
@@ -9,7 +9,7 @@ use crate::traits::query::{
 };
 use crate::ty::query::queries;
 use crate::ty::query::QueryDescription;
-use crate::ty::subst::SubstsRef;
+use crate::ty::subst::{GenericArg, SubstsRef};
 use crate::ty::{self, ParamEnvAnd, Ty, TyCtxt};
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
 
@@ -1114,10 +1114,10 @@ rustc_queries! {
         }
 
         /// Do not call this query directly: invoke `normalize_erasing_regions` instead.
-        query normalize_ty_after_erasing_regions(
-            goal: ParamEnvAnd<'tcx, Ty<'tcx>>
-        ) -> Ty<'tcx> {
-            desc { "normalizing `{:?}`", goal }
+        query normalize_generic_arg_after_erasing_regions(
+            goal: ParamEnvAnd<'tcx, GenericArg<'tcx>>
+        ) -> GenericArg<'tcx> {
+            desc { "normalizing `{}`", goal.value }
         }
 
         query implied_outlives_bounds(
diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs
index a5efea9e5fa4d..b1fb02a67b3ff 100644
--- a/src/librustc/traits/structural_impls.rs
+++ b/src/librustc/traits/structural_impls.rs
@@ -273,6 +273,20 @@ impl<'tcx> TypeVisitor<'tcx> for BoundNamesCollector {
         t.super_visit_with(self)
     }
 
+    fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
+        match c.val {
+            ty::ConstKind::Bound(debruijn, bound_var) if debruijn == self.binder_index => {
+                self.types.insert(
+                    bound_var.as_u32(),
+                    Symbol::intern(&format!("^{}", bound_var.as_u32())),
+                );
+            }
+            _ => (),
+        }
+
+        c.super_visit_with(self)
+    }
+
     fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
         match r {
             ty::ReLateBound(index, br) if *index == self.binder_index => match br {
diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs
index 4adca6c7d9772..3f4f2407f1e6e 100644
--- a/src/librustc/ty/fold.rs
+++ b/src/librustc/ty/fold.rs
@@ -978,17 +978,27 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector {
         // ignore the inputs to a projection, as they may not appear
         // in the normalized form
         if self.just_constrained {
-            match t.kind {
-                ty::Projection(..) | ty::Opaque(..) => {
-                    return false;
-                }
-                _ => {}
+            if let ty::Projection(..) | ty::Opaque(..) = t.kind {
+                return false;
             }
         }
 
         t.super_visit_with(self)
     }
 
+    fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
+        // if we are only looking for "constrained" region, we have to
+        // ignore the inputs of an unevaluated const, as they may not appear
+        // in the normalized form
+        if self.just_constrained {
+            if let ty::ConstKind::Unevaluated(..) = c.val {
+                return false;
+            }
+        }
+
+        c.super_visit_with(self)
+    }
+
     fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
         if let ty::ReLateBound(debruijn, br) = *r {
             if debruijn == self.current_index {
diff --git a/src/librustc/ty/normalize_erasing_regions.rs b/src/librustc/ty/normalize_erasing_regions.rs
index cbaabd8e1f137..2f0a57c59eb14 100644
--- a/src/librustc/ty/normalize_erasing_regions.rs
+++ b/src/librustc/ty/normalize_erasing_regions.rs
@@ -4,8 +4,8 @@
 //!
 //! The methods in this file use a `TypeFolder` to recursively process
 //! contents, invoking the underlying
-//! `normalize_ty_after_erasing_regions` query for each type found
-//! within. (This underlying query is what is cached.)
+//! `normalize_generic_arg_after_erasing_regions` query for each type
+//! or constant found within. (This underlying query is what is cached.)
 
 use crate::ty::fold::{TypeFoldable, TypeFolder};
 use crate::ty::subst::{Subst, SubstsRef};
@@ -94,6 +94,12 @@ impl TypeFolder<'tcx> for NormalizeAfterErasingRegionsFolder<'tcx> {
     }
 
     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        self.tcx.normalize_ty_after_erasing_regions(self.param_env.and(ty))
+        let arg = self.param_env.and(ty.into());
+        self.tcx.normalize_generic_arg_after_erasing_regions(arg).expect_ty()
+    }
+
+    fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+        let arg = self.param_env.and(c.into());
+        self.tcx.normalize_generic_arg_after_erasing_regions(arg).expect_const()
     }
 }
diff --git a/src/librustc/ty/query/keys.rs b/src/librustc/ty/query/keys.rs
index 6073d3a545f6d..6be1f04efca2b 100644
--- a/src/librustc/ty/query/keys.rs
+++ b/src/librustc/ty/query/keys.rs
@@ -5,7 +5,7 @@ use crate::mir;
 use crate::traits;
 use crate::ty::fast_reject::SimplifiedType;
 use crate::ty::query::caches::DefaultCacheSelector;
-use crate::ty::subst::SubstsRef;
+use crate::ty::subst::{GenericArg, SubstsRef};
 use crate::ty::{self, Ty, TyCtxt};
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
 use rustc_span::symbol::Symbol;
@@ -194,6 +194,17 @@ impl<'tcx> Key for ty::PolyTraitRef<'tcx> {
     }
 }
 
+impl<'tcx> Key for GenericArg<'tcx> {
+    type CacheSelector = DefaultCacheSelector;
+
+    fn query_crate(&self) -> CrateNum {
+        LOCAL_CRATE
+    }
+    fn default_span(&self, _: TyCtxt<'_>) -> Span {
+        DUMMY_SP
+    }
+}
+
 impl<'tcx> Key for &'tcx ty::Const<'tcx> {
     type CacheSelector = DefaultCacheSelector;
 
diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs
index 32ba13b1dbe9a..1094eb4940346 100644
--- a/src/librustc/ty/query/mod.rs
+++ b/src/librustc/ty/query/mod.rs
@@ -31,7 +31,7 @@ use crate::traits::specialization_graph;
 use crate::traits::Clauses;
 use crate::traits::{self, Vtable};
 use crate::ty::steal::Steal;
-use crate::ty::subst::SubstsRef;
+use crate::ty::subst::{GenericArg, SubstsRef};
 use crate::ty::util::AlwaysRequiresDrop;
 use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
 use crate::util::common::ErrorReported;
diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs
index a3acc14856e1f..0f4485a705046 100644
--- a/src/librustc/ty/subst.rs
+++ b/src/librustc/ty/subst.rs
@@ -128,6 +128,14 @@ impl<'tcx> GenericArg<'tcx> {
             _ => bug!("expected a type, but found another kind"),
         }
     }
+
+    /// Unpack the `GenericArg` as a const when it is known certainly to be a const.
+    pub fn expect_const(self) -> &'tcx ty::Const<'tcx> {
+        match self.unpack() {
+            GenericArgKind::Const(c) => c,
+            _ => bug!("expected a const, but found another kind"),
+        }
+    }
 }
 
 impl<'a, 'tcx> Lift<'tcx> for GenericArg<'a> {
diff --git a/src/librustc_session/session.rs b/src/librustc_session/session.rs
index 80f59aff69137..b3d75143c5639 100644
--- a/src/librustc_session/session.rs
+++ b/src/librustc_session/session.rs
@@ -150,7 +150,7 @@ pub struct PerfStats {
     /// Total number of values canonicalized queries constructed.
     pub queries_canonicalized: AtomicUsize,
     /// Number of times this query is invoked.
-    pub normalize_ty_after_erasing_regions: AtomicUsize,
+    pub normalize_generic_arg_after_erasing_regions: AtomicUsize,
     /// Number of times this query is invoked.
     pub normalize_projection_ty: AtomicUsize,
 }
@@ -707,8 +707,8 @@ impl Session {
             self.perf_stats.queries_canonicalized.load(Ordering::Relaxed)
         );
         println!(
-            "normalize_ty_after_erasing_regions:            {}",
-            self.perf_stats.normalize_ty_after_erasing_regions.load(Ordering::Relaxed)
+            "normalize_generic_arg_after_erasing_regions:   {}",
+            self.perf_stats.normalize_generic_arg_after_erasing_regions.load(Ordering::Relaxed)
         );
         println!(
             "normalize_projection_ty:                       {}",
@@ -1080,7 +1080,7 @@ fn build_session_(
             symbol_hash_time: Lock::new(Duration::from_secs(0)),
             decode_def_path_tables_time: Lock::new(Duration::from_secs(0)),
             queries_canonicalized: AtomicUsize::new(0),
-            normalize_ty_after_erasing_regions: AtomicUsize::new(0),
+            normalize_generic_arg_after_erasing_regions: AtomicUsize::new(0),
             normalize_projection_ty: AtomicUsize::new(0),
         },
         code_stats: Default::default(),
diff --git a/src/librustc_trait_selection/traits/project.rs b/src/librustc_trait_selection/traits/project.rs
index 6b14f6959bfb9..0968f470d13c0 100644
--- a/src/librustc_trait_selection/traits/project.rs
+++ b/src/librustc_trait_selection/traits/project.rs
@@ -387,6 +387,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
     }
 
     fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+        let constant = constant.super_fold_with(self);
         constant.eval(self.selcx.tcx(), self.param_env)
     }
 }
diff --git a/src/librustc_trait_selection/traits/query/normalize.rs b/src/librustc_trait_selection/traits/query/normalize.rs
index 99412fafcfa8d..77128bc8c8ab4 100644
--- a/src/librustc_trait_selection/traits/query/normalize.rs
+++ b/src/librustc_trait_selection/traits/query/normalize.rs
@@ -191,6 +191,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
     }
 
     fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+        let constant = constant.super_fold_with(self);
         constant.eval(self.infcx.tcx, self.param_env)
     }
 }
diff --git a/src/librustc_traits/normalize_erasing_regions.rs b/src/librustc_traits/normalize_erasing_regions.rs
index c2fb237a05b54..065cf38eb2490 100644
--- a/src/librustc_traits/normalize_erasing_regions.rs
+++ b/src/librustc_traits/normalize_erasing_regions.rs
@@ -1,23 +1,24 @@
 use rustc::traits::query::NoSolution;
 use rustc::ty::query::Providers;
-use rustc::ty::{self, ParamEnvAnd, Ty, TyCtxt};
+use rustc::ty::subst::GenericArg;
+use rustc::ty::{self, ParamEnvAnd, TyCtxt};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_trait_selection::traits::query::normalize::AtExt;
 use rustc_trait_selection::traits::{Normalized, ObligationCause};
 use std::sync::atomic::Ordering;
 
 crate fn provide(p: &mut Providers<'_>) {
-    *p = Providers { normalize_ty_after_erasing_regions, ..*p };
+    *p = Providers { normalize_generic_arg_after_erasing_regions, ..*p };
 }
 
-fn normalize_ty_after_erasing_regions<'tcx>(
+fn normalize_generic_arg_after_erasing_regions<'tcx>(
     tcx: TyCtxt<'tcx>,
-    goal: ParamEnvAnd<'tcx, Ty<'tcx>>,
-) -> Ty<'tcx> {
-    debug!("normalize_ty_after_erasing_regions(goal={:#?})", goal);
+    goal: ParamEnvAnd<'tcx, GenericArg<'tcx>>,
+) -> GenericArg<'tcx> {
+    debug!("normalize_generic_arg_after_erasing_regions(goal={:#?})", goal);
 
     let ParamEnvAnd { param_env, value } = goal;
-    tcx.sess.perf_stats.normalize_ty_after_erasing_regions.fetch_add(1, Ordering::Relaxed);
+    tcx.sess.perf_stats.normalize_generic_arg_after_erasing_regions.fetch_add(1, Ordering::Relaxed);
     tcx.infer_ctxt().enter(|infcx| {
         let cause = ObligationCause::dummy();
         match infcx.at(&cause, param_env).normalize(&value) {
diff --git a/src/test/mir-opt/inline/inline-into-box-place.rs b/src/test/mir-opt/inline/inline-into-box-place.rs
index f368bdef6f8e2..fcb7b4c4fe69d 100644
--- a/src/test/mir-opt/inline/inline-into-box-place.rs
+++ b/src/test/mir-opt/inline/inline-into-box-place.rs
@@ -1,6 +1,7 @@
 // ignore-tidy-linelength
 // ignore-wasm32-bare compiled with panic=abort by default
 // compile-flags: -Z mir-opt-level=3
+// only-64bit FIXME: the mir representation of RawVec depends on ptr size
 #![feature(box_syntax)]
 
 fn main() {
@@ -55,7 +56,7 @@ fn main() {
 //   StorageLive(_2);
 //   _2 = Box(std::vec::Vec<u32>);
 //   _4 = &mut (*_2);
-//   ((*_4).0: alloc::raw_vec::RawVec<u32>) = const alloc::raw_vec::RawVec::<u32>::NEW;
+//   ((*_4).0: alloc::raw_vec::RawVec<u32>) = const ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), undef_mask: UndefMask { blocks: [65535], len: Size { raw: 16 } }, size: Size { raw: 16 }, align: Align { pow2: 3 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }: alloc::raw_vec::RawVec::<u32>;
 //   ((*_4).1: usize) = const 0usize;
 //   _1 = move _2;
 //   StorageDead(_2);
diff --git a/src/test/ui/associated-const/defaults-cyclic-fail.rs b/src/test/ui/associated-const/defaults-cyclic-fail.rs
index 9b899ee316a0e..9fb1bbebc9610 100644
--- a/src/test/ui/associated-const/defaults-cyclic-fail.rs
+++ b/src/test/ui/associated-const/defaults-cyclic-fail.rs
@@ -1,9 +1,9 @@
 // build-fail
+//~^ ERROR cycle detected when normalizing `<() as Tr>::A`
 
 // Cyclic assoc. const defaults don't error unless *used*
 trait Tr {
     const A: u8 = Self::B;
-    //~^ ERROR cycle detected when const-evaluating + checking `Tr::A`
 
     const B: u8 = Self::A;
 }
diff --git a/src/test/ui/associated-const/defaults-cyclic-fail.stderr b/src/test/ui/associated-const/defaults-cyclic-fail.stderr
index 940182d4aa676..6b2fbe5be4e30 100644
--- a/src/test/ui/associated-const/defaults-cyclic-fail.stderr
+++ b/src/test/ui/associated-const/defaults-cyclic-fail.stderr
@@ -1,30 +1,42 @@
-error[E0391]: cycle detected when const-evaluating + checking `Tr::A`
-  --> $DIR/defaults-cyclic-fail.rs:5:5
+error[E0391]: cycle detected when normalizing `<() as Tr>::A`
+   |
+note: ...which requires const-evaluating + checking `Tr::A`...
+  --> $DIR/defaults-cyclic-fail.rs:6:5
    |
 LL |     const A: u8 = Self::B;
    |     ^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires const-evaluating + checking `Tr::A`...
+  --> $DIR/defaults-cyclic-fail.rs:6:5
    |
+LL |     const A: u8 = Self::B;
+   |     ^^^^^^^^^^^^^^^^^^^^^^
 note: ...which requires const-evaluating `Tr::A`...
-  --> $DIR/defaults-cyclic-fail.rs:5:19
+  --> $DIR/defaults-cyclic-fail.rs:6:5
    |
 LL |     const A: u8 = Self::B;
-   |                   ^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+   = note: ...which requires normalizing `<() as Tr>::B`...
+note: ...which requires const-evaluating + checking `Tr::B`...
+  --> $DIR/defaults-cyclic-fail.rs:8:5
+   |
+LL |     const B: u8 = Self::A;
+   |     ^^^^^^^^^^^^^^^^^^^^^^
 note: ...which requires const-evaluating + checking `Tr::B`...
   --> $DIR/defaults-cyclic-fail.rs:8:5
    |
 LL |     const B: u8 = Self::A;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 note: ...which requires const-evaluating `Tr::B`...
-  --> $DIR/defaults-cyclic-fail.rs:8:19
+  --> $DIR/defaults-cyclic-fail.rs:8:5
    |
 LL |     const B: u8 = Self::A;
-   |                   ^^^^^^^
-   = note: ...which again requires const-evaluating + checking `Tr::A`, completing the cycle
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+   = note: ...which again requires normalizing `<() as Tr>::A`, completing the cycle
 note: cycle used when const-evaluating `main`
-  --> $DIR/defaults-cyclic-fail.rs:16:16
+  --> $DIR/defaults-cyclic-fail.rs:14:1
    |
-LL |     assert_eq!(<() as Tr>::A, 0);
-   |                ^^^^^^^^^^^^^
+LL | fn main() {
+   | ^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/const-size_of-cycle.stderr b/src/test/ui/consts/const-size_of-cycle.stderr
index c03b7a19ffc61..aac3622c6de40 100644
--- a/src/test/ui/consts/const-size_of-cycle.stderr
+++ b/src/test/ui/consts/const-size_of-cycle.stderr
@@ -25,7 +25,7 @@ note: ...which requires const-evaluating + checking `std::intrinsics::size_of`..
 LL |     pub fn size_of<T>() -> usize;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: ...which requires computing layout of `Foo`...
-   = note: ...which requires normalizing `ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: All, def_id: None }, value: [u8; _] }`...
+   = note: ...which requires normalizing `[u8; _]`...
    = note: ...which again requires const-evaluating + checking `Foo::bytes::{{constant}}#0`, completing the cycle
 note: cycle used when processing `Foo`
   --> $DIR/const-size_of-cycle.rs:7:1