about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-09-12 13:29:56 +0000
committerbors <bors@rust-lang.org>2021-09-12 13:29:56 +0000
commitc7dbe7a830100c70d59994fd940bf75bb6e39b39 (patch)
treea2588214f00d5970ce090c65cafad1b53b9f5814
parent9ef27bf7dc50a8b51435579b4f2e86f7ee3f7a94 (diff)
parent146aee66b1cc33ce0db4bc7ffe01d88145d6fb1f (diff)
downloadrust-c7dbe7a830100c70d59994fd940bf75bb6e39b39.tar.gz
rust-c7dbe7a830100c70d59994fd940bf75bb6e39b39.zip
Auto merge of #88881 - Manishearth:rollup-alohfwx, r=Manishearth
Rollup of 7 pull requests

Successful merges:

 - #88336 ( Detect stricter constraints on gats where clauses in impls vs trait)
 - #88677 (rustc: Remove local variable IDs from `Export`s)
 - #88699 (Remove extra unshallow from cherry-pick checker)
 - #88709 (generic_const_exprs: use thir for abstract consts instead of mir)
 - #88711 (Rework DepthFirstSearch API)
 - #88810 (rustdoc: Cleanup `clean` part 1)
 - #88813 (explicitly link to external `ena` docs)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_data_structures/src/graph/iterate/mod.rs54
-rw-r--r--compiler/rustc_data_structures/src/graph/iterate/tests.rs16
-rw-r--r--compiler/rustc_data_structures/src/graph/mod.rs2
-rw-r--r--compiler/rustc_data_structures/src/lib.rs1
-rw-r--r--compiler/rustc_data_structures/src/stable_hasher.rs6
-rw-r--r--compiler/rustc_hir/src/def.rs5
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs88
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note.rs18
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs21
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs14
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs42
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs17
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs5
-rw-r--r--compiler/rustc_middle/src/hir/exports.rs13
-rw-r--r--compiler/rustc_middle/src/mir/abstract_const.rs38
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs1
-rw-r--r--compiler/rustc_middle/src/mir/query.rs14
-rw-r--r--compiler/rustc_middle/src/query/mod.rs12
-rw-r--r--compiler/rustc_middle/src/thir.rs3
-rw-r--r--compiler/rustc_middle/src/thir/abstract_const.rs61
-rw-r--r--compiler/rustc_middle/src/thir/visit.rs (renamed from compiler/rustc_mir_build/src/thir/visit.rs)6
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs5
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs6
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/mod.rs1
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs1
-rw-r--r--compiler/rustc_privacy/src/lib.rs2
-rw-r--r--compiler/rustc_query_impl/src/on_disk_cache.rs3
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs4
-rw-r--r--compiler/rustc_resolve/src/imports.rs5
-rw-r--r--compiler/rustc_resolve/src/lib.rs3
-rw-r--r--compiler/rustc_serialize/src/serialize.rs12
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs425
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs10
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs2
-rw-r--r--compiler/rustc_typeck/src/check/method/suggest.rs2
-rw-r--r--src/bootstrap/doc.rs8
-rwxr-xr-xsrc/ci/scripts/verify-backported-commits.sh8
-rw-r--r--src/librustdoc/clean/inline.rs11
-rw-r--r--src/librustdoc/clean/mod.rs36
-rw-r--r--src/librustdoc/clean/types.rs11
-rw-r--r--src/librustdoc/clean/utils.rs54
-rw-r--r--src/librustdoc/formats/cache.rs3
-rw-r--r--src/librustdoc/html/render/mod.rs46
-rw-r--r--src/librustdoc/visit_lib.rs2
-rw-r--r--src/test/rustdoc/synthetic_auto/no-redundancy.rs2
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs11
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.stderr10
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr2
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/closures.stderr2
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr8
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs35
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr10
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr12
-rw-r--r--src/test/ui/const-generics/issues/issue-67375.full.stderr6
-rw-r--r--src/test/ui/const-generics/issues/issue-67945-2.full.stderr3
-rw-r--r--src/test/ui/generic-associated-types/impl_bounds.rs2
-rw-r--r--src/test/ui/generic-associated-types/impl_bounds.stderr20
-rw-r--r--src/test/ui/generic-associated-types/issue-86787.stderr4
-rw-r--r--src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs13
-rw-r--r--src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr11
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs4
67 files changed, 688 insertions, 576 deletions
diff --git a/compiler/rustc_data_structures/src/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs
index 09b91083a63..a9db3497b23 100644
--- a/compiler/rustc_data_structures/src/graph/iterate/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs
@@ -83,8 +83,58 @@ impl<G> DepthFirstSearch<'graph, G>
 where
     G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
 {
-    pub fn new(graph: &'graph G, start_node: G::Node) -> Self {
-        Self { graph, stack: vec![start_node], visited: BitSet::new_empty(graph.num_nodes()) }
+    pub fn new(graph: &'graph G) -> Self {
+        Self { graph, stack: vec![], visited: BitSet::new_empty(graph.num_nodes()) }
+    }
+
+    /// Version of `push_start_node` that is convenient for chained
+    /// use.
+    pub fn with_start_node(mut self, start_node: G::Node) -> Self {
+        self.push_start_node(start_node);
+        self
+    }
+
+    /// Pushes another start node onto the stack. If the node
+    /// has not already been visited, then you will be able to
+    /// walk its successors (and so forth) after the current
+    /// contents of the stack are drained. If multiple start nodes
+    /// are added into the walk, then their mutual successors
+    /// will all be walked. You can use this method once the
+    /// iterator has been completely drained to add additional
+    /// start nodes.
+    pub fn push_start_node(&mut self, start_node: G::Node) {
+        if self.visited.insert(start_node) {
+            self.stack.push(start_node);
+        }
+    }
+
+    /// Searches all nodes reachable from the current start nodes.
+    /// This is equivalent to just invoke `next` repeatedly until
+    /// you get a `None` result.
+    pub fn complete_search(&mut self) {
+        while let Some(_) = self.next() {}
+    }
+
+    /// Returns true if node has been visited thus far.
+    /// A node is considered "visited" once it is pushed
+    /// onto the internal stack; it may not yet have been yielded
+    /// from the iterator. This method is best used after
+    /// the iterator is completely drained.
+    pub fn visited(&self, node: G::Node) -> bool {
+        self.visited.contains(node)
+    }
+}
+
+impl<G> std::fmt::Debug for DepthFirstSearch<'_, G>
+where
+    G: ?Sized + DirectedGraph + WithNumNodes + WithSuccessors,
+{
+    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let mut f = fmt.debug_set();
+        for n in self.visited.iter() {
+            f.entry(&n);
+        }
+        f.finish()
     }
 }
 
diff --git a/compiler/rustc_data_structures/src/graph/iterate/tests.rs b/compiler/rustc_data_structures/src/graph/iterate/tests.rs
index 0e038e88b22..c498c289337 100644
--- a/compiler/rustc_data_structures/src/graph/iterate/tests.rs
+++ b/compiler/rustc_data_structures/src/graph/iterate/tests.rs
@@ -20,3 +20,19 @@ fn is_cyclic() {
     assert!(!is_cyclic(&diamond_acyclic));
     assert!(is_cyclic(&diamond_cyclic));
 }
+
+#[test]
+fn dfs() {
+    let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3), (3, 0)]);
+
+    let result: Vec<usize> = DepthFirstSearch::new(&graph).with_start_node(0).collect();
+    assert_eq!(result, vec![0, 2, 3, 1]);
+}
+
+#[test]
+fn dfs_debug() {
+    let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3), (3, 0)]);
+    let mut dfs = DepthFirstSearch::new(&graph).with_start_node(0);
+    dfs.complete_search();
+    assert_eq!(format!("{{0, 1, 2, 3}}"), format!("{:?}", dfs));
+}
diff --git a/compiler/rustc_data_structures/src/graph/mod.rs b/compiler/rustc_data_structures/src/graph/mod.rs
index dff22855629..3560df6e5e2 100644
--- a/compiler/rustc_data_structures/src/graph/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/mod.rs
@@ -32,7 +32,7 @@ where
     where
         Self: WithNumNodes,
     {
-        iterate::DepthFirstSearch::new(self, from)
+        iterate::DepthFirstSearch::new(self).with_start_node(from)
     }
 }
 
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index d128a688e75..dd6a17b92ae 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -21,6 +21,7 @@
 #![feature(iter_map_while)]
 #![feature(maybe_uninit_uninit_array)]
 #![feature(min_specialization)]
+#![feature(never_type)]
 #![feature(type_alias_impl_trait)]
 #![feature(new_uninit)]
 #![feature(nll)]
diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs
index 18b352cf3b0..354f9dd93cc 100644
--- a/compiler/rustc_data_structures/src/stable_hasher.rs
+++ b/compiler/rustc_data_structures/src/stable_hasher.rs
@@ -209,6 +209,12 @@ impl_stable_hash_via_hash!(i128);
 impl_stable_hash_via_hash!(char);
 impl_stable_hash_via_hash!(());
 
+impl<CTX> HashStable<CTX> for ! {
+    fn hash_stable(&self, _ctx: &mut CTX, _hasher: &mut StableHasher) {
+        unreachable!()
+    }
+}
+
 impl<CTX> HashStable<CTX> for ::std::num::NonZeroU32 {
     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
         self.get().hash_stable(ctx, hasher)
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index 853415c4173..cb668eb35e0 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -598,6 +598,11 @@ impl<Id> Res<Id> {
         }
     }
 
+    #[track_caller]
+    pub fn expect_non_local<OtherId>(self) -> Res<OtherId> {
+        self.map_id(|_| panic!("unexpected `Res::Local`"))
+    }
+
     pub fn macro_kind(self) -> Option<MacroKind> {
         match self {
             Res::Def(DefKind::Macro(kind), _) => Some(kind),
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
index 61c8113d052..43aa8a6efce 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
@@ -2,7 +2,7 @@
 
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use crate::infer::lexical_region_resolve::RegionResolutionError;
-use crate::infer::{Subtype, ValuePairs};
+use crate::infer::{SubregionOrigin, Subtype, ValuePairs};
 use crate::traits::ObligationCauseCode::CompareImplMethodObligation;
 use rustc_errors::ErrorReported;
 use rustc_hir as hir;
@@ -11,44 +11,53 @@ use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
 use rustc_middle::ty::error::ExpectedFound;
 use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_span::{MultiSpan, Span};
+use rustc_span::{MultiSpan, Span, Symbol};
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     /// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`.
     pub(super) fn try_report_impl_not_conforming_to_trait(&self) -> Option<ErrorReported> {
-        if let Some(ref error) = self.error {
-            debug!("try_report_impl_not_conforming_to_trait {:?}", error);
-            if let RegionResolutionError::SubSupConflict(
-                _,
-                var_origin,
-                sub_origin,
-                _sub,
-                sup_origin,
-                _sup,
-            ) = error.clone()
-            {
-                if let (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) =
-                    (&sup_origin, &sub_origin)
+        let error = self.error.as_ref()?;
+        debug!("try_report_impl_not_conforming_to_trait {:?}", error);
+        if let RegionResolutionError::SubSupConflict(
+            _,
+            var_origin,
+            sub_origin,
+            _sub,
+            sup_origin,
+            _sup,
+        ) = error.clone()
+        {
+            if let (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) = (&sup_origin, &sub_origin) {
+                if let (
+                    ValuePairs::Types(sub_expected_found),
+                    ValuePairs::Types(sup_expected_found),
+                    CompareImplMethodObligation { trait_item_def_id, .. },
+                ) = (&sub_trace.values, &sup_trace.values, &sub_trace.cause.code)
                 {
-                    if let (
-                        ValuePairs::Types(sub_expected_found),
-                        ValuePairs::Types(sup_expected_found),
-                        CompareImplMethodObligation { trait_item_def_id, .. },
-                    ) = (&sub_trace.values, &sup_trace.values, &sub_trace.cause.code)
-                    {
-                        if sup_expected_found == sub_expected_found {
-                            self.emit_err(
-                                var_origin.span(),
-                                sub_expected_found.expected,
-                                sub_expected_found.found,
-                                *trait_item_def_id,
-                            );
-                            return Some(ErrorReported);
-                        }
+                    if sup_expected_found == sub_expected_found {
+                        self.emit_err(
+                            var_origin.span(),
+                            sub_expected_found.expected,
+                            sub_expected_found.found,
+                            *trait_item_def_id,
+                        );
+                        return Some(ErrorReported);
                     }
                 }
             }
         }
+        if let RegionResolutionError::ConcreteFailure(origin, _, _) = error.clone() {
+            if let SubregionOrigin::CompareImplTypeObligation {
+                span,
+                item_name,
+                impl_item_def_id,
+                trait_item_def_id,
+            } = origin
+            {
+                self.emit_associated_type_err(span, item_name, impl_item_def_id, trait_item_def_id);
+                return Some(ErrorReported);
+            }
+        }
         None
     }
 
@@ -107,6 +116,25 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         }
         err.emit();
     }
+
+    fn emit_associated_type_err(
+        &self,
+        span: Span,
+        item_name: Symbol,
+        impl_item_def_id: DefId,
+        trait_item_def_id: DefId,
+    ) {
+        let impl_sp = self.tcx().def_span(impl_item_def_id);
+        let trait_sp = self.tcx().def_span(trait_item_def_id);
+        let mut err = self
+            .tcx()
+            .sess
+            .struct_span_err(span, &format!("`impl` associated type signature for `{}` doesn't match `trait` associated type signature", item_name));
+        err.span_label(impl_sp, &format!("found"));
+        err.span_label(trait_sp, &format!("expected"));
+
+        err.emit();
+    }
 }
 
 struct TypeParamSpanVisitor<'tcx> {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
index 4bc59a4baf5..5f99a23f86e 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs
@@ -99,6 +99,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                     "...so that the definition in impl matches the definition from the trait",
                 );
             }
+            infer::CompareImplTypeObligation { span, .. } => {
+                label_or_note(
+                    span,
+                    "...so that the definition in impl matches the definition from the trait",
+                );
+            }
         }
     }
 
@@ -356,6 +362,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 trait_item_def_id,
                 &format!("`{}: {}`", sup, sub),
             ),
+            infer::CompareImplTypeObligation {
+                span,
+                item_name,
+                impl_item_def_id,
+                trait_item_def_id,
+            } => self.report_extra_impl_obligation(
+                span,
+                item_name,
+                impl_item_def_id,
+                trait_item_def_id,
+                &format!("`{}: {}`", sup, sub),
+            ),
         }
     }
 
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index bc98a3aa3f9..354b8e26d53 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -427,6 +427,15 @@ pub enum SubregionOrigin<'tcx> {
         impl_item_def_id: DefId,
         trait_item_def_id: DefId,
     },
+
+    /// Comparing the signature and requirements of an impl associated type
+    /// against the containing trait
+    CompareImplTypeObligation {
+        span: Span,
+        item_name: Symbol,
+        impl_item_def_id: DefId,
+        trait_item_def_id: DefId,
+    },
 }
 
 // `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger.
@@ -1810,6 +1819,7 @@ impl<'tcx> SubregionOrigin<'tcx> {
             ReferenceOutlivesReferent(_, a) => a,
             CallReturn(a) => a,
             CompareImplMethodObligation { span, .. } => span,
+            CompareImplTypeObligation { span, .. } => span,
         }
     }
 
@@ -1833,6 +1843,17 @@ impl<'tcx> SubregionOrigin<'tcx> {
                 trait_item_def_id,
             },
 
+            traits::ObligationCauseCode::CompareImplTypeObligation {
+                item_name,
+                impl_item_def_id,
+                trait_item_def_id,
+            } => SubregionOrigin::CompareImplTypeObligation {
+                span: cause.span,
+                item_name,
+                impl_item_def_id,
+                trait_item_def_id,
+            },
+
             _ => default(),
         }
     }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 5f01cfa6a7d..2a0332a1124 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -26,6 +26,7 @@ use rustc_middle::middle::cstore::{ForeignModule, LinkagePreference, NativeLib};
 use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
 use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
 use rustc_middle::mir::{self, Body, Promoted};
+use rustc_middle::thir;
 use rustc_middle::ty::codec::TyDecoder;
 use rustc_middle::ty::{self, Ty, TyCtxt, Visibility};
 use rustc_serialize::{opaque, Decodable, Decoder};
@@ -541,7 +542,7 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span {
     }
 }
 
-impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [mir::abstract_const::Node<'tcx>] {
+impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [thir::abstract_const::Node<'tcx>] {
     fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> {
         ty::codec::RefDecodable::decode(d)
     }
@@ -1020,10 +1021,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
     }
 
     /// Iterates over each child of the given item.
-    fn each_child_of_item<F>(&self, id: DefIndex, mut callback: F, sess: &Session)
-    where
-        F: FnMut(Export<hir::HirId>),
-    {
+    fn each_child_of_item(&self, id: DefIndex, mut callback: impl FnMut(Export), sess: &Session) {
         if let Some(data) = &self.root.proc_macro_data {
             /* If we are loading as a proc macro, we want to return the view of this crate
              * as a proc macro crate.
@@ -1199,14 +1197,14 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
             .decode((self, tcx))
     }
 
-    fn get_mir_abstract_const(
+    fn get_thir_abstract_const(
         &self,
         tcx: TyCtxt<'tcx>,
         id: DefIndex,
-    ) -> Result<Option<&'tcx [mir::abstract_const::Node<'tcx>]>, ErrorReported> {
+    ) -> Result<Option<&'tcx [thir::abstract_const::Node<'tcx>]>, ErrorReported> {
         self.root
             .tables
-            .mir_abstract_consts
+            .thir_abstract_consts
             .get(self, id)
             .map_or(Ok(None), |v| Ok(Some(v.decode((self, tcx)))))
     }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 41839c58021..50074803bbe 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -5,7 +5,6 @@ use crate::rmeta::encoder;
 
 use rustc_ast as ast;
 use rustc_data_structures::stable_map::FxHashMap;
-use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
@@ -117,7 +116,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
     optimized_mir => { tcx.arena.alloc(cdata.get_optimized_mir(tcx, def_id.index)) }
     mir_for_ctfe => { tcx.arena.alloc(cdata.get_mir_for_ctfe(tcx, def_id.index)) }
     promoted_mir => { tcx.arena.alloc(cdata.get_promoted_mir(tcx, def_id.index)) }
-    mir_abstract_const => { cdata.get_mir_abstract_const(tcx, def_id.index) }
+    thir_abstract_const => { cdata.get_thir_abstract_const(tcx, def_id.index) }
     unused_generic_params => { cdata.get_unused_generic_params(def_id.index) }
     const_param_default => { tcx.mk_const(cdata.get_const_param_default(tcx, def_id.index)) }
     mir_const_qualif => { cdata.mir_const_qualif(def_id.index) }
@@ -326,28 +325,27 @@ pub fn provide(providers: &mut Providers) {
             // (restrict scope of mutable-borrow of `visible_parent_map`)
             {
                 let visible_parent_map = &mut visible_parent_map;
-                let mut add_child =
-                    |bfs_queue: &mut VecDeque<_>, child: &Export<hir::HirId>, parent: DefId| {
-                        if child.vis != ty::Visibility::Public {
-                            return;
-                        }
+                let mut add_child = |bfs_queue: &mut VecDeque<_>, child: &Export, parent: DefId| {
+                    if child.vis != ty::Visibility::Public {
+                        return;
+                    }
 
-                        if let Some(child) = child.res.opt_def_id() {
-                            match visible_parent_map.entry(child) {
-                                Entry::Occupied(mut entry) => {
-                                    // If `child` is defined in crate `cnum`, ensure
-                                    // that it is mapped to a parent in `cnum`.
-                                    if child.is_local() && entry.get().is_local() {
-                                        entry.insert(parent);
-                                    }
-                                }
-                                Entry::Vacant(entry) => {
+                    if let Some(child) = child.res.opt_def_id() {
+                        match visible_parent_map.entry(child) {
+                            Entry::Occupied(mut entry) => {
+                                // If `child` is defined in crate `cnum`, ensure
+                                // that it is mapped to a parent in `cnum`.
+                                if child.is_local() && entry.get().is_local() {
                                     entry.insert(parent);
-                                    bfs_queue.push_back(child);
                                 }
                             }
+                            Entry::Vacant(entry) => {
+                                entry.insert(parent);
+                                bfs_queue.push_back(child);
+                            }
                         }
-                    };
+                    }
+                };
 
                 while let Some(def) = bfs_queue.pop_front() {
                     for child in tcx.item_children(def).iter() {
@@ -393,11 +391,7 @@ impl CStore {
         self.get_crate_data(def.krate).get_visibility(def.index)
     }
 
-    pub fn item_children_untracked(
-        &self,
-        def_id: DefId,
-        sess: &Session,
-    ) -> Vec<Export<hir::HirId>> {
+    pub fn item_children_untracked(&self, def_id: DefId, sess: &Session) -> Vec<Export> {
         let mut result = vec![];
         self.get_crate_data(def_id.krate).each_child_of_item(
             def_id.index,
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index d8b9a479976..1b24e5eae98 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -23,6 +23,7 @@ use rustc_middle::middle::exported_symbols::{
     metadata_symbol_name, ExportedSymbol, SymbolExportLevel,
 };
 use rustc_middle::mir::interpret;
+use rustc_middle::thir;
 use rustc_middle::traits::specialization_graph;
 use rustc_middle::ty::codec::TyEncoder;
 use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt};
@@ -344,7 +345,7 @@ impl<'a, 'tcx> TyEncoder<'tcx> for EncodeContext<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for &'tcx [mir::abstract_const::Node<'tcx>] {
+impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for &'tcx [thir::abstract_const::Node<'tcx>] {
     fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
         (**self).encode(s)
     }
@@ -1065,14 +1066,7 @@ impl EncodeContext<'a, 'tcx> {
         // items - we encode information about proc-macros later on.
         let reexports = if !self.is_proc_macro {
             match tcx.module_exports(local_def_id) {
-                Some(exports) => {
-                    let hir = self.tcx.hir();
-                    self.lazy(
-                        exports
-                            .iter()
-                            .map(|export| export.map_id(|id| hir.local_def_id_to_hir_id(id))),
-                    )
-                }
+                Some(exports) => self.lazy(exports),
                 _ => Lazy::empty(),
             }
         } else {
@@ -1304,9 +1298,10 @@ impl EncodeContext<'a, 'tcx> {
             if encode_const {
                 record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- self.tcx.mir_for_ctfe(def_id));
 
-                let abstract_const = self.tcx.mir_abstract_const(def_id);
+                // FIXME(generic_const_exprs): this feels wrong to have in `encode_mir`
+                let abstract_const = self.tcx.thir_abstract_const(def_id);
                 if let Ok(Some(abstract_const)) = abstract_const {
-                    record!(self.tables.mir_abstract_consts[def_id.to_def_id()] <- abstract_const);
+                    record!(self.tables.thir_abstract_consts[def_id.to_def_id()] <- abstract_const);
                 }
             }
             record!(self.tables.promoted_mir[def_id.to_def_id()] <- self.tcx.promoted_mir(def_id));
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index a487753f462..575ab04ab24 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -15,6 +15,7 @@ use rustc_middle::hir::exports::Export;
 use rustc_middle::middle::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib};
 use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
 use rustc_middle::mir;
+use rustc_middle::thir;
 use rustc_middle::ty::{self, ReprOptions, Ty};
 use rustc_serialize::opaque::Encoder;
 use rustc_session::config::SymbolManglingVersion;
@@ -305,7 +306,7 @@ define_tables! {
     mir: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
     mir_for_ctfe: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
     promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>,
-    mir_abstract_consts: Table<DefIndex, Lazy!(&'tcx [mir::abstract_const::Node<'tcx>])>,
+    thir_abstract_consts: Table<DefIndex, Lazy!(&'tcx [thir::abstract_const::Node<'tcx>])>,
     const_defaults: Table<DefIndex, Lazy<rustc_middle::ty::Const<'tcx>>>,
     unused_generic_params: Table<DefIndex, Lazy<FiniteBitSet<u32>>>,
     // `def_keys` and `def_path_hashes` represent a lazy version of a
@@ -359,7 +360,7 @@ struct RenderedConst(String);
 
 #[derive(MetadataEncodable, MetadataDecodable)]
 struct ModData {
-    reexports: Lazy<[Export<hir::HirId>]>,
+    reexports: Lazy<[Export]>,
     expansion: ExpnId,
 }
 
diff --git a/compiler/rustc_middle/src/hir/exports.rs b/compiler/rustc_middle/src/hir/exports.rs
index be9e38aca65..f37b976fba6 100644
--- a/compiler/rustc_middle/src/hir/exports.rs
+++ b/compiler/rustc_middle/src/hir/exports.rs
@@ -11,23 +11,18 @@ use std::fmt::Debug;
 
 /// This is the replacement export map. It maps a module to all of the exports
 /// within.
-pub type ExportMap<Id> = FxHashMap<LocalDefId, Vec<Export<Id>>>;
+pub type ExportMap = FxHashMap<LocalDefId, Vec<Export>>;
 
 #[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
-pub struct Export<Id> {
+pub struct Export {
     /// The name of the target.
     pub ident: Ident,
     /// The resolution of the target.
-    pub res: Res<Id>,
+    /// Local variables cannot be exported, so this `Res` doesn't need the ID parameter.
+    pub res: Res<!>,
     /// The span of the target.
     pub span: Span,
     /// The visibility of the export.
     /// We include non-`pub` exports for hygienic macros that get used from extern crates.
     pub vis: ty::Visibility,
 }
-
-impl<Id> Export<Id> {
-    pub fn map_id<R>(self, map: impl FnMut(Id) -> R) -> Export<R> {
-        Export { ident: self.ident, res: self.res.map_id(map), span: self.span, vis: self.vis }
-    }
-}
diff --git a/compiler/rustc_middle/src/mir/abstract_const.rs b/compiler/rustc_middle/src/mir/abstract_const.rs
deleted file mode 100644
index 1ef10241143..00000000000
--- a/compiler/rustc_middle/src/mir/abstract_const.rs
+++ /dev/null
@@ -1,38 +0,0 @@
-//! A subset of a mir body used for const evaluatability checking.
-use crate::mir::{self, CastKind};
-use crate::ty::{self, Ty};
-
-rustc_index::newtype_index! {
-    /// An index into an `AbstractConst`.
-    pub struct NodeId {
-        derive [HashStable]
-        DEBUG_FORMAT = "n{}",
-    }
-}
-
-/// A node of an `AbstractConst`.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
-pub enum Node<'tcx> {
-    Leaf(&'tcx ty::Const<'tcx>),
-    Binop(mir::BinOp, NodeId, NodeId),
-    UnaryOp(mir::UnOp, NodeId),
-    FunctionCall(NodeId, &'tcx [NodeId]),
-    Cast(CastKind, NodeId, Ty<'tcx>),
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
-pub enum NotConstEvaluatable {
-    Error(rustc_errors::ErrorReported),
-    MentionsInfer,
-    MentionsParam,
-}
-
-impl From<rustc_errors::ErrorReported> for NotConstEvaluatable {
-    fn from(e: rustc_errors::ErrorReported) -> NotConstEvaluatable {
-        NotConstEvaluatable::Error(e)
-    }
-}
-
-TrivialTypeFoldableAndLiftImpls! {
-    NotConstEvaluatable,
-}
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index e40227530cd..ebdf354b905 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -40,7 +40,6 @@ use self::graph_cyclic_cache::GraphIsCyclicCache;
 use self::predecessors::{PredecessorCache, Predecessors};
 pub use self::query::*;
 
-pub mod abstract_const;
 pub mod coverage;
 mod generic_graph;
 pub mod generic_graphviz;
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index 1bdb6ca012b..567f65e83d9 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -1,6 +1,6 @@
 //! Values computed by queries that use MIR.
 
-use crate::mir::{abstract_const, Body, Promoted};
+use crate::mir::{Body, Promoted};
 use crate::ty::{self, Ty, TyCtxt};
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::vec_map::VecMap;
@@ -431,16 +431,4 @@ impl<'tcx> TyCtxt<'tcx> {
             self.mir_for_ctfe(def.did)
         }
     }
-
-    #[inline]
-    pub fn mir_abstract_const_opt_const_arg(
-        self,
-        def: ty::WithOptConstParam<DefId>,
-    ) -> Result<Option<&'tcx [abstract_const::Node<'tcx>]>, ErrorReported> {
-        if let Some((did, param_did)) = def.as_const_arg() {
-            self.mir_abstract_const_of_const_arg((did, param_did))
-        } else {
-            self.mir_abstract_const(def.did)
-        }
-    }
 }
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index d6f3b6f3248..5748e5319e0 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -303,17 +303,17 @@ rustc_queries! {
     }
 
     /// Try to build an abstract representation of the given constant.
-    query mir_abstract_const(
+    query thir_abstract_const(
         key: DefId
-    ) -> Result<Option<&'tcx [mir::abstract_const::Node<'tcx>]>, ErrorReported> {
+    ) -> Result<Option<&'tcx [thir::abstract_const::Node<'tcx>]>, ErrorReported> {
         desc {
             |tcx| "building an abstract representation for {}", tcx.def_path_str(key),
         }
     }
     /// Try to build an abstract representation of the given constant.
-    query mir_abstract_const_of_const_arg(
+    query thir_abstract_const_of_const_arg(
         key: (LocalDefId, DefId)
-    ) -> Result<Option<&'tcx [mir::abstract_const::Node<'tcx>]>, ErrorReported> {
+    ) -> Result<Option<&'tcx [thir::abstract_const::Node<'tcx>]>, ErrorReported> {
         desc {
             |tcx|
             "building an abstract representation for the const argument {}",
@@ -1189,7 +1189,7 @@ rustc_queries! {
         desc { "traits in scope at a block" }
     }
 
-    query module_exports(def_id: LocalDefId) -> Option<&'tcx [Export<LocalDefId>]> {
+    query module_exports(def_id: LocalDefId) -> Option<&'tcx [Export]> {
         desc { |tcx| "looking up items exported by `{}`", tcx.def_path_str(def_id.to_def_id()) }
     }
 
@@ -1401,7 +1401,7 @@ rustc_queries! {
         eval_always
         desc { "fetching what a crate is named" }
     }
-    query item_children(def_id: DefId) -> &'tcx [Export<hir::HirId>] {
+    query item_children(def_id: DefId) -> &'tcx [Export] {
         desc { |tcx| "collecting child items of `{}`", tcx.def_path_str(def_id) }
     }
     query extern_mod_stmt_cnum(def_id: LocalDefId) -> Option<CrateNum> {
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 91a64e163e7..8d6fd1e729d 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -33,6 +33,9 @@ use rustc_target::asm::InlineAsmRegOrRegClass;
 use std::fmt;
 use std::ops::Index;
 
+pub mod abstract_const;
+pub mod visit;
+
 newtype_index! {
     /// An index to an [`Arm`] stored in [`Thir::arms`]
     #[derive(HashStable)]
diff --git a/compiler/rustc_middle/src/thir/abstract_const.rs b/compiler/rustc_middle/src/thir/abstract_const.rs
new file mode 100644
index 00000000000..f80beadd6e5
--- /dev/null
+++ b/compiler/rustc_middle/src/thir/abstract_const.rs
@@ -0,0 +1,61 @@
+//! A subset of a mir body used for const evaluatability checking.
+use crate::mir;
+use crate::ty::{self, Ty, TyCtxt};
+use rustc_errors::ErrorReported;
+
+rustc_index::newtype_index! {
+    /// An index into an `AbstractConst`.
+    pub struct NodeId {
+        derive [HashStable]
+        DEBUG_FORMAT = "n{}",
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
+pub enum CastKind {
+    /// thir::ExprKind::As
+    As,
+    /// thir::ExprKind::Use
+    Use,
+}
+
+/// A node of an `AbstractConst`.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
+pub enum Node<'tcx> {
+    Leaf(&'tcx ty::Const<'tcx>),
+    Binop(mir::BinOp, NodeId, NodeId),
+    UnaryOp(mir::UnOp, NodeId),
+    FunctionCall(NodeId, &'tcx [NodeId]),
+    Cast(CastKind, NodeId, Ty<'tcx>),
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
+pub enum NotConstEvaluatable {
+    Error(ErrorReported),
+    MentionsInfer,
+    MentionsParam,
+}
+
+impl From<ErrorReported> for NotConstEvaluatable {
+    fn from(e: ErrorReported) -> NotConstEvaluatable {
+        NotConstEvaluatable::Error(e)
+    }
+}
+
+TrivialTypeFoldableAndLiftImpls! {
+    NotConstEvaluatable,
+}
+
+impl<'tcx> TyCtxt<'tcx> {
+    #[inline]
+    pub fn thir_abstract_const_opt_const_arg(
+        self,
+        def: ty::WithOptConstParam<rustc_hir::def_id::DefId>,
+    ) -> Result<Option<&'tcx [Node<'tcx>]>, ErrorReported> {
+        if let Some((did, param_did)) = def.as_const_arg() {
+            self.thir_abstract_const_of_const_arg((did, param_did))
+        } else {
+            self.thir_abstract_const(def.did)
+        }
+    }
+}
diff --git a/compiler/rustc_mir_build/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index 51c371b8720..7fc15e02fcd 100644
--- a/compiler/rustc_mir_build/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -1,4 +1,6 @@
-use rustc_middle::thir::{self, *};
+use super::{
+    Arm, Block, Expr, ExprKind, Guard, InlineAsmOperand, Pat, PatKind, Stmt, StmtKind, Thir,
+};
 use rustc_middle::ty::Const;
 
 pub trait Visitor<'a, 'tcx: 'a>: Sized {
@@ -101,7 +103,7 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp
                 visitor.visit_expr(&visitor.thir()[field]);
             }
         }
-        Adt(box thir::Adt {
+        Adt(box crate::thir::Adt {
             ref fields,
             ref base,
             adt_def: _,
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 74edb17fe32..e21a2d1034c 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -9,7 +9,7 @@ pub mod specialization_graph;
 mod structural_impls;
 
 use crate::infer::canonical::Canonical;
-use crate::mir::abstract_const::NotConstEvaluatable;
+use crate::thir::abstract_const::NotConstEvaluatable;
 use crate::ty::subst::SubstsRef;
 use crate::ty::{self, AdtKind, Ty, TyCtxt};
 
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 4edb6a327b0..8b70692960d 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -12,6 +12,7 @@ use crate::mir::{
     self,
     interpret::{AllocId, Allocation},
 };
+use crate::thir;
 use crate::ty::subst::SubstsRef;
 use crate::ty::{self, List, Ty, TyCtxt};
 use rustc_data_structures::fx::FxHashMap;
@@ -362,7 +363,7 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [(ty::Predicate<'tcx>,
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::Node<'tcx>] {
+impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [thir::abstract_const::Node<'tcx>] {
     fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
         Ok(decoder.tcx().arena.alloc_from_iter(
             (0..decoder.read_usize()?)
@@ -372,7 +373,7 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::N
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::NodeId] {
+impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [thir::abstract_const::NodeId] {
     fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
         Ok(decoder.tcx().arena.alloc_from_iter(
             (0..decoder.read_usize()?)
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index fddfd6e435c..cd1e38445ae 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -127,7 +127,7 @@ pub struct ResolverOutputs {
     pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
     pub maybe_unused_trait_imports: FxHashSet<LocalDefId>,
     pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
-    pub export_map: ExportMap<LocalDefId>,
+    pub export_map: ExportMap,
     pub glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
     /// Extern prelude entries. The value is `true` if the entry was introduced
     /// via `extern crate` item and not `--extern` option or compiler built-in.
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 0a760a740dc..0ee740a6463 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -47,10 +47,12 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
     // Ensure unsafeck is ran before we steal the THIR.
     match def {
         ty::WithOptConstParam { did, const_param_did: Some(const_param_did) } => {
-            tcx.ensure().thir_check_unsafety_for_const_arg((did, const_param_did))
+            tcx.ensure().thir_check_unsafety_for_const_arg((did, const_param_did));
+            tcx.ensure().thir_abstract_const_of_const_arg((did, const_param_did));
         }
         ty::WithOptConstParam { did, const_param_did: None } => {
-            tcx.ensure().thir_check_unsafety(did)
+            tcx.ensure().thir_check_unsafety(did);
+            tcx.ensure().thir_abstract_const(did);
         }
     }
 
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 05a5fcef16a..0e82b187201 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -1,5 +1,5 @@
 use crate::build::ExprCategory;
-use crate::thir::visit::{self, Visitor};
+use rustc_middle::thir::visit::{self, Visitor};
 
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
diff --git a/compiler/rustc_mir_build/src/thir/mod.rs b/compiler/rustc_mir_build/src/thir/mod.rs
index e5123d8ef0c..ddbe1b0b69c 100644
--- a/compiler/rustc_mir_build/src/thir/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/mod.rs
@@ -11,4 +11,3 @@ crate mod cx;
 crate mod pattern;
 
 mod util;
-pub mod visit;
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 9a074c10ef4..90d7cbee976 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -306,7 +306,6 @@ fn mir_promoted(
     // this point, before we steal the mir-const result.
     // Also this means promotion can rely on all const checks having been done.
     let _ = tcx.mir_const_qualif_opt_const_arg(def);
-    let _ = tcx.mir_abstract_const_opt_const_arg(def.to_global());
     let mut body = tcx.mir_const(def).steal();
 
     let mut required_consts = Vec::new();
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 35e25e52dc5..391e4305423 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -19,8 +19,8 @@ use rustc_hir::{AssocItemKind, HirIdSet, Node, PatKind};
 use rustc_middle::bug;
 use rustc_middle::hir::map::Map;
 use rustc_middle::middle::privacy::{AccessLevel, AccessLevels};
-use rustc_middle::mir::abstract_const::Node as ACNode;
 use rustc_middle::span_bug;
+use rustc_middle::thir::abstract_const::Node as ACNode;
 use rustc_middle::ty::fold::TypeVisitor;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::subst::{InternalSubsts, Subst};
diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs
index a54d1556b3e..bfd36bfb2db 100644
--- a/compiler/rustc_query_impl/src/on_disk_cache.rs
+++ b/compiler/rustc_query_impl/src/on_disk_cache.rs
@@ -9,6 +9,7 @@ use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::dep_graph::{DepNode, DepNodeIndex, SerializedDepNodeIndex};
 use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
 use rustc_middle::mir::{self, interpret};
+use rustc_middle::thir;
 use rustc_middle::ty::codec::{RefDecodable, TyDecoder, TyEncoder};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_query_system::dep_graph::DepContext;
@@ -921,7 +922,7 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>>
     }
 }
 
-impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [mir::abstract_const::Node<'tcx>] {
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [thir::abstract_const::Node<'tcx>] {
     fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
         RefDecodable::decode(d)
     }
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 2ee483d850e..55f2b04c4f1 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -228,7 +228,6 @@ impl<'a> Resolver<'a> {
     crate fn build_reduced_graph_external(&mut self, module: Module<'a>) {
         let def_id = module.def_id().expect("unpopulated module without a def-id");
         for child in self.cstore().item_children_untracked(def_id, self.session) {
-            let child = child.map_id(|_| panic!("unexpected id"));
             let parent_scope = ParentScope::module(module, self);
             BuildReducedGraphVisitor { r: self, parent_scope }
                 .build_reduced_graph_for_external_crate_res(child);
@@ -946,9 +945,10 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
     }
 
     /// Builds the reduced graph for a single item in an external crate.
-    fn build_reduced_graph_for_external_crate_res(&mut self, child: Export<NodeId>) {
+    fn build_reduced_graph_for_external_crate_res(&mut self, child: Export) {
         let parent = self.parent_scope.module;
         let Export { ident, res, vis, span } = child;
+        let res = res.expect_non_local();
         let expansion = self.parent_scope.expansion;
         // Record primary definitions.
         match res {
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index dfb6d89a0d1..d4782edbc13 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -11,7 +11,6 @@ use crate::{NameBinding, NameBindingKind, PathResult, PrivacyError, ToNameBindin
 
 use rustc_ast::unwrap_or;
 use rustc_ast::NodeId;
-use rustc_ast_lowering::ResolverAstLowering;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::ptr_key::PtrKey;
 use rustc_errors::{pluralize, struct_span_err, Applicability};
@@ -1387,13 +1386,13 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
 
         let mut reexports = Vec::new();
 
-        module.for_each_child(self.r, |this, ident, _, binding| {
+        module.for_each_child(self.r, |_, ident, _, binding| {
             // Filter away ambiguous imports and anything that has def-site hygiene.
             // FIXME: Implement actual cross-crate hygiene.
             let is_good_import =
                 binding.is_import() && !binding.is_ambiguity() && !ident.span.from_expansion();
             if is_good_import || binding.is_macro_def() {
-                let res = binding.res().map_id(|id| this.local_def_id(id));
+                let res = binding.res().expect_non_local();
                 if res != def::Res::Err {
                     reexports.push(Export { ident, res, span: binding.span, vis: binding.vis });
                 }
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 7fb1e92440b..d76ba80e42e 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -14,6 +14,7 @@
 #![feature(crate_visibility_modifier)]
 #![feature(format_args_capture)]
 #![feature(iter_zip)]
+#![feature(never_type)]
 #![feature(nll)]
 #![recursion_limit = "256"]
 #![allow(rustdoc::private_intra_doc_links)]
@@ -911,7 +912,7 @@ pub struct Resolver<'a> {
 
     /// `CrateNum` resolutions of `extern crate` items.
     extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
-    export_map: ExportMap<LocalDefId>,
+    export_map: ExportMap,
     trait_map: Option<NodeMap<Vec<TraitCandidate>>>,
 
     /// A map from nodes to anonymous modules.
diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs
index ecc8dae0480..e32e4493726 100644
--- a/compiler/rustc_serialize/src/serialize.rs
+++ b/compiler/rustc_serialize/src/serialize.rs
@@ -366,6 +366,18 @@ direct_serialize_impls! {
     char emit_char read_char
 }
 
+impl<S: Encoder> Encodable<S> for ! {
+    fn encode(&self, _s: &mut S) -> Result<(), S::Error> {
+        unreachable!()
+    }
+}
+
+impl<D: Decoder> Decodable<D> for ! {
+    fn decode(_d: &mut D) -> Result<!, D::Error> {
+        unreachable!()
+    }
+}
+
 impl<S: Encoder> Encodable<S> for ::std::num::NonZeroU32 {
     fn encode(&self, s: &mut S) -> Result<(), S::Error> {
         s.emit_u32(self.get())
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index ddabe5967d7..24fa5007f1e 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -6,16 +6,16 @@
 //! this is not as easy.
 //!
 //! In this case we try to build an abstract representation of this constant using
-//! `mir_abstract_const` which can then be checked for structural equality with other
+//! `thir_abstract_const` which can then be checked for structural equality with other
 //! generic constants mentioned in the `caller_bounds` of the current environment.
 use rustc_errors::ErrorReported;
 use rustc_hir::def::DefKind;
-use rustc_index::bit_set::BitSet;
 use rustc_index::vec::IndexVec;
 use rustc_infer::infer::InferCtxt;
-use rustc_middle::mir::abstract_const::{Node, NodeId, NotConstEvaluatable};
+use rustc_middle::mir;
 use rustc_middle::mir::interpret::ErrorHandled;
-use rustc_middle::mir::{self, Rvalue, StatementKind, TerminatorKind};
+use rustc_middle::thir;
+use rustc_middle::thir::abstract_const::{self, Node, NodeId, NotConstEvaluatable};
 use rustc_middle::ty::subst::{Subst, SubstsRef};
 use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
 use rustc_session::lint;
@@ -196,7 +196,7 @@ impl<'tcx> AbstractConst<'tcx> {
         tcx: TyCtxt<'tcx>,
         uv: ty::Unevaluated<'tcx, ()>,
     ) -> Result<Option<AbstractConst<'tcx>>, ErrorReported> {
-        let inner = tcx.mir_abstract_const_opt_const_arg(uv.def)?;
+        let inner = tcx.thir_abstract_const_opt_const_arg(uv.def)?;
         debug!("AbstractConst::new({:?}) = {:?}", uv, inner);
         Ok(inner.map(|inner| AbstractConst { inner, substs: uv.substs(tcx) }))
     }
@@ -223,35 +223,24 @@ impl<'tcx> AbstractConst<'tcx> {
     }
 }
 
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-struct WorkNode<'tcx> {
-    node: Node<'tcx>,
-    span: Span,
-    used: bool,
-}
-
 struct AbstractConstBuilder<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
-    body: &'a mir::Body<'tcx>,
+    body_id: thir::ExprId,
+    body: &'a thir::Thir<'tcx>,
     /// The current WIP node tree.
-    ///
-    /// We require all nodes to be used in the final abstract const,
-    /// so we store this here. Note that we also consider nodes as used
-    /// if they are mentioned in an assert, so some used nodes are never
-    /// actually reachable by walking the [`AbstractConst`].
-    nodes: IndexVec<NodeId, WorkNode<'tcx>>,
-    locals: IndexVec<mir::Local, NodeId>,
-    /// We only allow field accesses if they access
-    /// the result of a checked operation.
-    checked_op_locals: BitSet<mir::Local>,
+    nodes: IndexVec<NodeId, Node<'tcx>>,
 }
 
 impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
+    fn root_span(&self) -> Span {
+        self.body.exprs[self.body_id].span
+    }
+
     fn error(&mut self, span: Option<Span>, msg: &str) -> Result<!, ErrorReported> {
         self.tcx
             .sess
-            .struct_span_err(self.body.span, "overly complex generic constant")
-            .span_label(span.unwrap_or(self.body.span), msg)
+            .struct_span_err(self.root_span(), "overly complex generic constant")
+            .span_label(span.unwrap_or(self.root_span()), msg)
             .help("consider moving this anonymous constant into a `const` function")
             .emit();
 
@@ -260,98 +249,49 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
 
     fn new(
         tcx: TyCtxt<'tcx>,
-        body: &'a mir::Body<'tcx>,
+        (body, body_id): (&'a thir::Thir<'tcx>, thir::ExprId),
     ) -> Result<Option<AbstractConstBuilder<'a, 'tcx>>, ErrorReported> {
-        let mut builder = AbstractConstBuilder {
-            tcx,
-            body,
-            nodes: IndexVec::new(),
-            locals: IndexVec::from_elem(NodeId::MAX, &body.local_decls),
-            checked_op_locals: BitSet::new_empty(body.local_decls.len()),
-        };
-
-        // We don't have to look at concrete constants, as we
-        // can just evaluate them.
-        if !body.is_polymorphic {
-            return Ok(None);
-        }
+        let builder = AbstractConstBuilder { tcx, body_id, body, nodes: IndexVec::new() };
 
-        // We only allow consts without control flow, so
-        // we check for cycles here which simplifies the
-        // rest of this implementation.
-        if body.is_cfg_cyclic() {
-            builder.error(None, "cyclic anonymous constants are forbidden")?;
+        struct IsThirPolymorphic<'a, 'tcx> {
+            is_poly: bool,
+            thir: &'a thir::Thir<'tcx>,
+            tcx: TyCtxt<'tcx>,
         }
 
-        Ok(Some(builder))
-    }
-
-    fn add_node(&mut self, node: Node<'tcx>, span: Span) -> NodeId {
-        // Mark used nodes.
-        match node {
-            Node::Leaf(_) => (),
-            Node::Binop(_, lhs, rhs) => {
-                self.nodes[lhs].used = true;
-                self.nodes[rhs].used = true;
-            }
-            Node::UnaryOp(_, input) => {
-                self.nodes[input].used = true;
-            }
-            Node::FunctionCall(func, nodes) => {
-                self.nodes[func].used = true;
-                nodes.iter().for_each(|&n| self.nodes[n].used = true);
+        use thir::visit;
+        impl<'a, 'tcx: 'a> visit::Visitor<'a, 'tcx> for IsThirPolymorphic<'a, 'tcx> {
+            fn thir(&self) -> &'a thir::Thir<'tcx> {
+                &self.thir
             }
-            Node::Cast(_, operand, _) => {
-                self.nodes[operand].used = true;
+
+            fn visit_expr(&mut self, expr: &thir::Expr<'tcx>) {
+                self.is_poly |= expr.ty.definitely_has_param_types_or_consts(self.tcx);
+                if self.is_poly == false {
+                    visit::walk_expr(self, expr)
+                }
             }
-        }
 
-        // Nodes start as unused.
-        self.nodes.push(WorkNode { node, span, used: false })
-    }
+            fn visit_pat(&mut self, pat: &thir::Pat<'tcx>) {
+                self.is_poly |= pat.ty.definitely_has_param_types_or_consts(self.tcx);
+                if self.is_poly == false {
+                    visit::walk_pat(self, pat);
+                }
+            }
 
-    fn place_to_local(
-        &mut self,
-        span: Span,
-        p: &mir::Place<'tcx>,
-    ) -> Result<mir::Local, ErrorReported> {
-        const ZERO_FIELD: mir::Field = mir::Field::from_usize(0);
-        // Do not allow any projections.
-        //
-        // One exception are field accesses on the result of checked operations,
-        // which are required to support things like `1 + 2`.
-        if let Some(p) = p.as_local() {
-            debug_assert!(!self.checked_op_locals.contains(p));
-            Ok(p)
-        } else if let &[mir::ProjectionElem::Field(ZERO_FIELD, _)] = p.projection.as_ref() {
-            // Only allow field accesses if the given local
-            // contains the result of a checked operation.
-            if self.checked_op_locals.contains(p.local) {
-                Ok(p.local)
-            } else {
-                self.error(Some(span), "unsupported projection")?;
+            fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) {
+                self.is_poly |= ct.definitely_has_param_types_or_consts(self.tcx);
             }
-        } else {
-            self.error(Some(span), "unsupported projection")?;
         }
-    }
 
-    fn operand_to_node(
-        &mut self,
-        span: Span,
-        op: &mir::Operand<'tcx>,
-    ) -> Result<NodeId, ErrorReported> {
-        debug!("operand_to_node: op={:?}", op);
-        match op {
-            mir::Operand::Copy(p) | mir::Operand::Move(p) => {
-                let local = self.place_to_local(span, p)?;
-                Ok(self.locals[local])
-            }
-            mir::Operand::Constant(ct) => match ct.literal {
-                mir::ConstantKind::Ty(ct) => Ok(self.add_node(Node::Leaf(ct), span)),
-                mir::ConstantKind::Val(..) => self.error(Some(span), "unsupported constant")?,
-            },
+        let mut is_poly_vis = IsThirPolymorphic { is_poly: false, thir: body, tcx };
+        visit::walk_expr(&mut is_poly_vis, &body[body_id]);
+        debug!("AbstractConstBuilder: is_poly={}", is_poly_vis.is_poly);
+        if is_poly_vis.is_poly == false {
+            return Ok(None);
         }
+
+        Ok(Some(builder))
     }
 
     /// We do not allow all binary operations in abstract consts, so filter disallowed ones.
@@ -373,170 +313,126 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
         }
     }
 
-    fn build_statement(&mut self, stmt: &mir::Statement<'tcx>) -> Result<(), ErrorReported> {
-        debug!("AbstractConstBuilder: stmt={:?}", stmt);
-        let span = stmt.source_info.span;
-        match stmt.kind {
-            StatementKind::Assign(box (ref place, ref rvalue)) => {
-                let local = self.place_to_local(span, place)?;
-                match *rvalue {
-                    Rvalue::Use(ref operand) => {
-                        self.locals[local] = self.operand_to_node(span, operand)?;
-                        Ok(())
-                    }
-                    Rvalue::BinaryOp(op, box (ref lhs, ref rhs)) if Self::check_binop(op) => {
-                        let lhs = self.operand_to_node(span, lhs)?;
-                        let rhs = self.operand_to_node(span, rhs)?;
-                        self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs), span);
-                        if op.is_checkable() {
-                            bug!("unexpected unchecked checkable binary operation");
-                        } else {
-                            Ok(())
-                        }
-                    }
-                    Rvalue::CheckedBinaryOp(op, box (ref lhs, ref rhs))
-                        if Self::check_binop(op) =>
-                    {
-                        let lhs = self.operand_to_node(span, lhs)?;
-                        let rhs = self.operand_to_node(span, rhs)?;
-                        self.locals[local] = self.add_node(Node::Binop(op, lhs, rhs), span);
-                        self.checked_op_locals.insert(local);
-                        Ok(())
-                    }
-                    Rvalue::UnaryOp(op, ref operand) if Self::check_unop(op) => {
-                        let operand = self.operand_to_node(span, operand)?;
-                        self.locals[local] = self.add_node(Node::UnaryOp(op, operand), span);
-                        Ok(())
-                    }
-                    Rvalue::Cast(cast_kind, ref operand, ty) => {
-                        let operand = self.operand_to_node(span, operand)?;
-                        self.locals[local] =
-                            self.add_node(Node::Cast(cast_kind, operand, ty), span);
-                        Ok(())
-                    }
-                    _ => self.error(Some(span), "unsupported rvalue")?,
-                }
-            }
-            // These are not actually relevant for us here, so we can ignore them.
-            StatementKind::AscribeUserType(..)
-            | StatementKind::StorageLive(_)
-            | StatementKind::StorageDead(_) => Ok(()),
-            _ => self.error(Some(stmt.source_info.span), "unsupported statement")?,
-        }
-    }
-
-    /// Possible return values:
-    ///
-    /// - `None`: unsupported terminator, stop building
-    /// - `Some(None)`: supported terminator, finish building
-    /// - `Some(Some(block))`: support terminator, build `block` next
-    fn build_terminator(
-        &mut self,
-        terminator: &mir::Terminator<'tcx>,
-    ) -> Result<Option<mir::BasicBlock>, ErrorReported> {
-        debug!("AbstractConstBuilder: terminator={:?}", terminator);
-        match terminator.kind {
-            TerminatorKind::Goto { target } => Ok(Some(target)),
-            TerminatorKind::Return => Ok(None),
-            TerminatorKind::Call {
-                ref func,
-                ref args,
-                destination: Some((ref place, target)),
-                // We do not care about `cleanup` here. Any branch which
-                // uses `cleanup` will fail const-eval and they therefore
-                // do not matter when checking for const evaluatability.
-                //
-                // Do note that even if `panic::catch_unwind` is made const,
-                // we still do not have to care about this, as we do not look
-                // into functions.
-                cleanup: _,
-                // Do not allow overloaded operators for now,
-                // we probably do want to allow this in the future.
-                //
-                // This is currently fairly irrelevant as it requires `const Trait`s.
-                from_hir_call: true,
-                fn_span,
-            } => {
-                let local = self.place_to_local(fn_span, place)?;
-                let func = self.operand_to_node(fn_span, func)?;
-                let args = self.tcx.arena.alloc_from_iter(
-                    args.iter()
-                        .map(|arg| self.operand_to_node(terminator.source_info.span, arg))
-                        .collect::<Result<Vec<NodeId>, _>>()?,
-                );
-                self.locals[local] = self.add_node(Node::FunctionCall(func, args), fn_span);
-                Ok(Some(target))
-            }
-            TerminatorKind::Assert { ref cond, expected: false, target, .. } => {
-                let p = match cond {
-                    mir::Operand::Copy(p) | mir::Operand::Move(p) => p,
-                    mir::Operand::Constant(_) => bug!("unexpected assert"),
-                };
-
-                const ONE_FIELD: mir::Field = mir::Field::from_usize(1);
-                debug!("proj: {:?}", p.projection);
-                if let Some(p) = p.as_local() {
-                    debug_assert!(!self.checked_op_locals.contains(p));
-                    // Mark locals directly used in asserts as used.
-                    //
-                    // This is needed because division does not use `CheckedBinop` but instead
-                    // adds an explicit assert for `divisor != 0`.
-                    self.nodes[self.locals[p]].used = true;
-                    return Ok(Some(target));
-                } else if let &[mir::ProjectionElem::Field(ONE_FIELD, _)] = p.projection.as_ref() {
-                    // Only allow asserts checking the result of a checked operation.
-                    if self.checked_op_locals.contains(p.local) {
-                        return Ok(Some(target));
-                    }
-                }
-
-                self.error(Some(terminator.source_info.span), "unsupported assertion")?;
-            }
-            _ => self.error(Some(terminator.source_info.span), "unsupported terminator")?,
-        }
-    }
-
-    /// Builds the abstract const by walking the mir from start to finish
-    /// and bailing out when encountering an unsupported operation.
+    /// Builds the abstract const by walking the thir and bailing out when
+    /// encountering an unspported operation.
     fn build(mut self) -> Result<&'tcx [Node<'tcx>], ErrorReported> {
-        let mut block = &self.body.basic_blocks()[mir::START_BLOCK];
-        // We checked for a cyclic cfg above, so this should terminate.
-        loop {
-            debug!("AbstractConstBuilder: block={:?}", block);
-            for stmt in block.statements.iter() {
-                self.build_statement(stmt)?;
-            }
+        debug!("Abstractconstbuilder::build: body={:?}", &*self.body);
+        self.recurse_build(self.body_id)?;
 
-            if let Some(next) = self.build_terminator(block.terminator())? {
-                block = &self.body.basic_blocks()[next];
-            } else {
-                break;
-            }
-        }
-
-        assert_eq!(self.locals[mir::RETURN_PLACE], self.nodes.last().unwrap());
         for n in self.nodes.iter() {
-            if let Node::Leaf(ty::Const { val: ty::ConstKind::Unevaluated(ct), ty: _ }) = n.node {
+            if let Node::Leaf(ty::Const { val: ty::ConstKind::Unevaluated(ct), ty: _ }) = n {
                 // `AbstractConst`s should not contain any promoteds as they require references which
                 // are not allowed.
                 assert_eq!(ct.promoted, None);
             }
         }
 
-        self.nodes[self.locals[mir::RETURN_PLACE]].used = true;
-        if let Some(&unused) = self.nodes.iter().find(|n| !n.used) {
-            self.error(Some(unused.span), "dead code")?;
-        }
+        Ok(self.tcx.arena.alloc_from_iter(self.nodes.into_iter()))
+    }
 
-        Ok(self.tcx.arena.alloc_from_iter(self.nodes.into_iter().map(|n| n.node)))
+    fn recurse_build(&mut self, node: thir::ExprId) -> Result<NodeId, ErrorReported> {
+        use thir::ExprKind;
+        let node = &self.body.exprs[node];
+        debug!("recurse_build: node={:?}", node);
+        Ok(match &node.kind {
+            // I dont know if handling of these 3 is correct
+            &ExprKind::Scope { value, .. } => self.recurse_build(value)?,
+            &ExprKind::PlaceTypeAscription { source, .. } |
+            &ExprKind::ValueTypeAscription { source, .. } => self.recurse_build(source)?,
+
+            // subtle: associated consts are literals this arm handles
+            // `<T as Trait>::ASSOC` as well as `12`
+            &ExprKind::Literal { literal, .. } => self.nodes.push(Node::Leaf(literal)),
+
+            ExprKind::Call { fun, args,  .. } => {
+                let fun = self.recurse_build(*fun)?;
+
+                let mut new_args = Vec::<NodeId>::with_capacity(args.len());
+                for &id in args.iter() {
+                    new_args.push(self.recurse_build(id)?);
+                }
+                let new_args = self.tcx.arena.alloc_slice(&new_args);
+                self.nodes.push(Node::FunctionCall(fun, new_args))
+            },
+            &ExprKind::Binary { op, lhs, rhs } if Self::check_binop(op) => {
+                let lhs = self.recurse_build(lhs)?;
+                let rhs = self.recurse_build(rhs)?;
+                self.nodes.push(Node::Binop(op, lhs, rhs))
+            }
+            &ExprKind::Unary { op, arg } if Self::check_unop(op) => {
+                let arg = self.recurse_build(arg)?;
+                self.nodes.push(Node::UnaryOp(op, arg))
+            },
+            // This is necessary so that the following compiles:
+            //
+            // ```
+            // fn foo<const N: usize>(a: [(); N + 1]) {
+            //     bar::<{ N + 1 }>();
+            // }
+            // ```
+            ExprKind::Block { body: thir::Block { stmts: box [], expr: Some(e), .. }} => self.recurse_build(*e)?,
+            // `ExprKind::Use` happens when a `hir::ExprKind::Cast` is a
+            // "coercion cast" i.e. using a coercion or is a no-op.
+            // This is important so that `N as usize as usize` doesnt unify with `N as usize`. (untested)
+            &ExprKind::Use { source } => {
+                let arg = self.recurse_build(source)?;
+                self.nodes.push(Node::Cast(abstract_const::CastKind::Use, arg, node.ty))
+            },
+            &ExprKind::Cast { source } => {
+                let arg = self.recurse_build(source)?;
+                self.nodes.push(Node::Cast(abstract_const::CastKind::As, arg, node.ty))
+            },
+
+            // FIXME(generic_const_exprs): We may want to support these.
+            ExprKind::AddressOf { .. }
+            | ExprKind::Borrow { .. }
+            | ExprKind::Deref { .. }
+            | ExprKind::Repeat { .. }
+            | ExprKind::Array { .. }
+            | ExprKind::Block { .. }
+            | ExprKind::NeverToAny { .. }
+            | ExprKind::Tuple { .. }
+            | ExprKind::Index { .. }
+            | ExprKind::Field { .. }
+            | ExprKind::ConstBlock { .. }
+            | ExprKind::Adt(_) => self.error(
+                    Some(node.span),
+                    "unsupported operation in generic constant, this may be supported in the future",
+                )?,
+
+            ExprKind::Match { .. }
+            // we dont permit let stmts so `VarRef` and `UpvarRef` cant happen
+            | ExprKind::VarRef { .. }
+            | ExprKind::UpvarRef { .. }
+            | ExprKind::Closure { .. }
+            | ExprKind::Let { .. } // let expressions imply control flow
+            | ExprKind::Loop { .. }
+            | ExprKind::Assign { .. }
+            | ExprKind::StaticRef { .. }
+            | ExprKind::LogicalOp { .. }
+            // we handle valid unary/binary ops above
+            | ExprKind::Unary { .. }
+            | ExprKind::Binary { .. }
+            | ExprKind::Break { .. }
+            | ExprKind::Continue { .. }
+            | ExprKind::If { .. }
+            | ExprKind::Pointer { .. } // dont know if this is correct
+            | ExprKind::ThreadLocalRef(_)
+            | ExprKind::LlvmInlineAsm { .. }
+            | ExprKind::Return { .. }
+            | ExprKind::Box { .. } // allocations not allowed in constants
+            | ExprKind::AssignOp { .. }
+            | ExprKind::InlineAsm { .. }
+            | ExprKind::Yield { .. } => self.error(Some(node.span), "unsupported operation in generic constant")?,
+        })
     }
 }
 
 /// Builds an abstract const, do not use this directly, but use `AbstractConst::new` instead.
-pub(super) fn mir_abstract_const<'tcx>(
+pub(super) fn thir_abstract_const<'tcx>(
     tcx: TyCtxt<'tcx>,
     def: ty::WithOptConstParam<LocalDefId>,
-) -> Result<Option<&'tcx [mir::abstract_const::Node<'tcx>]>, ErrorReported> {
+) -> Result<Option<&'tcx [thir::abstract_const::Node<'tcx>]>, ErrorReported> {
     if tcx.features().generic_const_exprs {
         match tcx.def_kind(def.did) {
             // FIXME(generic_const_exprs): We currently only do this for anonymous constants,
@@ -547,8 +443,16 @@ pub(super) fn mir_abstract_const<'tcx>(
             DefKind::AnonConst => (),
             _ => return Ok(None),
         }
-        let body = tcx.mir_const(def).borrow();
-        AbstractConstBuilder::new(tcx, &body)?.map(AbstractConstBuilder::build).transpose()
+
+        let body = tcx.thir_body(def);
+        if body.0.borrow().exprs.is_empty() {
+            // type error in constant, there is no thir
+            return Err(ErrorReported);
+        }
+
+        AbstractConstBuilder::new(tcx, (&*body.0.borrow(), body.1))?
+            .map(AbstractConstBuilder::build)
+            .transpose()
     } else {
         Ok(None)
     }
@@ -682,11 +586,16 @@ pub(super) fn try_unify<'tcx>(
                 && iter::zip(a_args, b_args)
                     .all(|(&an, &bn)| try_unify(tcx, a.subtree(an), b.subtree(bn)))
         }
-        (Node::Cast(a_cast_kind, a_operand, a_ty), Node::Cast(b_cast_kind, b_operand, b_ty))
-            if (a_ty == b_ty) && (a_cast_kind == b_cast_kind) =>
+        (Node::Cast(a_kind, a_operand, a_ty), Node::Cast(b_kind, b_operand, b_ty))
+            if (a_ty == b_ty) && (a_kind == b_kind) =>
         {
             try_unify(tcx, a.subtree(a_operand), b.subtree(b_operand))
         }
-        _ => false,
+        // use this over `_ => false` to make adding variants to `Node` less error prone
+        (Node::Cast(..), _)
+        | (Node::FunctionCall(..), _)
+        | (Node::UnaryOp(..), _)
+        | (Node::Binop(..), _)
+        | (Node::Leaf(..), _) => false,
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 52367661a4c..761b217c78f 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -19,7 +19,7 @@ use rustc_hir::intravisit::Visitor;
 use rustc_hir::GenericParam;
 use rustc_hir::Item;
 use rustc_hir::Node;
-use rustc_middle::mir::abstract_const::NotConstEvaluatable;
+use rustc_middle::thir::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::ExpectedFound;
 use rustc_middle::ty::fold::TypeFolder;
 use rustc_middle::ty::{
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 18abcc72bce..b376f429292 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -5,8 +5,8 @@ use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProce
 use rustc_errors::ErrorReported;
 use rustc_hir as hir;
 use rustc_infer::traits::{SelectionError, TraitEngine, TraitEngineExt as _, TraitObligation};
-use rustc_middle::mir::abstract_const::NotConstEvaluatable;
 use rustc_middle::mir::interpret::ErrorHandled;
+use rustc_middle::thir::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::ToPredicate;
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 44c67524383..ef208c44471 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -827,16 +827,16 @@ pub fn provide(providers: &mut ty::query::Providers) {
         vtable_entries,
         vtable_trait_upcasting_coercion_new_vptr_slot,
         subst_and_check_impossible_predicates,
-        mir_abstract_const: |tcx, def_id| {
+        thir_abstract_const: |tcx, def_id| {
             let def_id = def_id.expect_local();
             if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
-                tcx.mir_abstract_const_of_const_arg(def)
+                tcx.thir_abstract_const_of_const_arg(def)
             } else {
-                const_evaluatable::mir_abstract_const(tcx, ty::WithOptConstParam::unknown(def_id))
+                const_evaluatable::thir_abstract_const(tcx, ty::WithOptConstParam::unknown(def_id))
             }
         },
-        mir_abstract_const_of_const_arg: |tcx, (did, param_did)| {
-            const_evaluatable::mir_abstract_const(
+        thir_abstract_const_of_const_arg: |tcx, (did, param_did)| {
+            const_evaluatable::thir_abstract_const(
                 tcx,
                 ty::WithOptConstParam { did, const_param_did: Some(param_did) },
             )
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 0ecfda19141..4922cf45a4a 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -836,7 +836,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>(
             //
             // This shouldn't really matter though as we can't really use any
             // constants which are not considered const evaluatable.
-            use rustc_middle::mir::abstract_const::Node;
+            use rustc_middle::thir::abstract_const::Node;
             if let Ok(Some(ct)) = AbstractConst::new(self.tcx, uv.shrink()) {
                 const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node.root() {
                     Node::Leaf(leaf) => {
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 9824b644c3e..f5be8bf0949 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -34,8 +34,8 @@ use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::LateBoundRegionConversionTime;
 use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
-use rustc_middle::mir::abstract_const::NotConstEvaluatable;
 use rustc_middle::mir::interpret::ErrorHandled;
+use rustc_middle::thir::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::fast_reject;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::relate::TypeRelation;
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index a746ad7ad4b..9744f4f6483 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -1655,7 +1655,7 @@ fn compute_all_traits(tcx: TyCtxt<'_>, (): ()) -> &[DefId] {
         tcx: TyCtxt<'_>,
         traits: &mut Vec<DefId>,
         external_mods: &mut FxHashSet<DefId>,
-        res: Res,
+        res: Res<!>,
     ) {
         match res {
             Res::Def(DefKind::Trait | DefKind::TraitAlias, def_id) => {
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index c8714117930..fbc7f19cb73 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -590,10 +590,18 @@ impl Step for Rustc {
         cargo.rustdocflag("-Znormalize-docs");
         cargo.rustdocflag("--show-type-layout");
         compile::rustc_cargo(builder, &mut cargo, target);
+        cargo.arg("-Zunstable-options");
         cargo.arg("-Zskip-rustdoc-fingerprint");
 
         // Only include compiler crates, no dependencies of those, such as `libc`.
+        // Do link to dependencies on `docs.rs` however using `rustdoc-map`.
         cargo.arg("--no-deps");
+        cargo.arg("-Zrustdoc-map");
+
+        // FIXME: `-Zrustdoc-map` does not yet correctly work for transitive dependencies,
+        // once this is no longer an issue the special case for `ena` can be removed.
+        cargo.rustdocflag("--extern-html-root-url");
+        cargo.rustdocflag("ena=https://docs.rs/ena/latest/");
 
         // Find dependencies for top level crates.
         let mut compiler_crates = HashSet::new();
diff --git a/src/ci/scripts/verify-backported-commits.sh b/src/ci/scripts/verify-backported-commits.sh
index 1023e4b0e28..d3da6d1ac91 100755
--- a/src/ci/scripts/verify-backported-commits.sh
+++ b/src/ci/scripts/verify-backported-commits.sh
@@ -18,14 +18,6 @@ verify_backported_commits_main() {
     exit 0
   fi
 
-  echo 'git: unshallowing the repository so we can check commits'
-  git fetch \
-    --no-tags \
-    --no-recurse-submodules \
-    --progress \
-    --prune \
-    --unshallow
-
   if [[ $ci_base_branch == "beta" ]]; then
     verify_cherries master "$BETA_LIMIT" \
       || exit 1
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 40b0175bb15..29834c82b3d 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -482,12 +482,13 @@ fn build_module(
     // visit each node at most once.
     for &item in cx.tcx.item_children(did).iter() {
         if item.vis == ty::Visibility::Public {
-            if let Some(def_id) = item.res.mod_def_id() {
+            let res = item.res.expect_non_local();
+            if let Some(def_id) = res.mod_def_id() {
                 if did == def_id || !visited.insert(def_id) {
                     continue;
                 }
             }
-            if let Res::PrimTy(p) = item.res {
+            if let Res::PrimTy(p) = res {
                 // Primitive types can't be inlined so generate an import instead.
                 let prim_ty = clean::PrimitiveType::from(p);
                 items.push(clean::Item {
@@ -500,7 +501,7 @@ fn build_module(
                         clean::ImportSource {
                             path: clean::Path {
                                 global: false,
-                                res: item.res,
+                                res,
                                 segments: vec![clean::PathSegment {
                                     name: prim_ty.as_sym(),
                                     args: clean::GenericArgs::AngleBracketed {
@@ -515,9 +516,7 @@ fn build_module(
                     ))),
                     cfg: None,
                 });
-            } else if let Some(i) =
-                try_inline(cx, did, None, item.res, item.ident.name, None, visited)
-            {
+            } else if let Some(i) = try_inline(cx, did, None, res, item.ident.name, None, visited) {
                 items.extend(i)
             }
         }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 6ffdf1df601..e281bbc59c2 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -164,14 +164,7 @@ impl Clean<Type> for (ty::TraitRef<'_>, &[TypeBinding]) {
             );
         }
         inline::record_extern_fqn(cx, trait_ref.def_id, kind);
-        let path = external_path(
-            cx,
-            cx.tcx.item_name(trait_ref.def_id),
-            Some(trait_ref.def_id),
-            true,
-            bounds.to_vec(),
-            trait_ref.substs,
-        );
+        let path = external_path(cx, trait_ref.def_id, true, bounds.to_vec(), trait_ref.substs);
 
         debug!("ty::TraitRef\n  subst: {:?}\n", trait_ref.substs);
 
@@ -906,7 +899,7 @@ impl Clean<bool> for hir::IsAuto {
 impl Clean<Type> for hir::TraitRef<'_> {
     fn clean(&self, cx: &mut DocContext<'_>) -> Type {
         let path = self.path.clean(cx);
-        resolve_type(cx, path, self.hir_ref_id)
+        resolve_type(cx, path)
     }
 }
 
@@ -1164,7 +1157,7 @@ impl Clean<Item> for ty::AssocItem {
 
 fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
     use rustc_hir::GenericParamCount;
-    let hir::Ty { hir_id, span, ref kind } = *hir_ty;
+    let hir::Ty { hir_id: _, span, ref kind } = *hir_ty;
     let qpath = match kind {
         hir::TyKind::Path(qpath) => qpath,
         _ => unreachable!(),
@@ -1271,7 +1264,7 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
                 return cx.enter_alias(ty_substs, lt_substs, ct_substs, |cx| ty.clean(cx));
             }
             let path = path.clean(cx);
-            resolve_type(cx, path, hir_id)
+            resolve_type(cx, path)
         }
         hir::QPath::Resolved(Some(ref qself), ref p) => {
             // Try to normalize `<X as Y>::T` to a type
@@ -1292,7 +1285,7 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
                 name: p.segments.last().expect("segments were empty").ident.name,
                 self_def_id: Some(DefId::local(qself.hir_id.owner.local_def_index)),
                 self_type: Box::new(qself.clean(cx)),
-                trait_: Box::new(resolve_type(cx, trait_path, hir_id)),
+                trait_: Box::new(resolve_type(cx, trait_path)),
             }
         }
         hir::QPath::TypeRelative(ref qself, ref segment) => {
@@ -1308,7 +1301,7 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
                 name: segment.ident.name,
                 self_def_id: res.opt_def_id(),
                 self_type: Box::new(qself.clean(cx)),
-                trait_: Box::new(resolve_type(cx, trait_path, hir_id)),
+                trait_: Box::new(resolve_type(cx, trait_path)),
             }
         }
         hir::QPath::LangItem(..) => bug!("clean: requiring documentation of lang item"),
@@ -1448,19 +1441,12 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                     AdtKind::Enum => ItemType::Enum,
                 };
                 inline::record_extern_fqn(cx, did, kind);
-                let path = external_path(cx, cx.tcx.item_name(did), None, false, vec![], substs);
+                let path = external_path(cx, did, false, vec![], substs);
                 ResolvedPath { path, did, is_generic: false }
             }
             ty::Foreign(did) => {
                 inline::record_extern_fqn(cx, did, ItemType::ForeignType);
-                let path = external_path(
-                    cx,
-                    cx.tcx.item_name(did),
-                    None,
-                    false,
-                    vec![],
-                    InternalSubsts::empty(),
-                );
+                let path = external_path(cx, did, false, vec![], InternalSubsts::empty());
                 ResolvedPath { path, did, is_generic: false }
             }
             ty::Dynamic(ref obj, ref reg) => {
@@ -1484,8 +1470,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
 
                 for did in dids {
                     let empty = cx.tcx.intern_substs(&[]);
-                    let path =
-                        external_path(cx, cx.tcx.item_name(did), Some(did), false, vec![], empty);
+                    let path = external_path(cx, did, false, vec![], empty);
                     inline::record_extern_fqn(cx, did, ItemType::Trait);
                     let bound = PolyTrait {
                         trait_: ResolvedPath { path, did, is_generic: false },
@@ -1502,8 +1487,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                     });
                 }
 
-                let path =
-                    external_path(cx, cx.tcx.item_name(did), Some(did), false, bindings, substs);
+                let path = external_path(cx, did, false, bindings, substs);
                 bounds.insert(
                     0,
                     PolyTrait {
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 454602481e3..b3c320555f9 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -212,7 +212,7 @@ impl ExternalCrate {
     crate fn keywords(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, Symbol)> {
         let root = self.def_id();
 
-        let as_keyword = |res: Res| {
+        let as_keyword = |res: Res<!>| {
             if let Res::Def(DefKind::Mod, def_id) = res {
                 let attrs = tcx.get_attrs(def_id);
                 let mut keyword = None;
@@ -243,7 +243,8 @@ impl ExternalCrate {
                         hir::ItemKind::Use(ref path, hir::UseKind::Single)
                             if item.vis.node.is_pub() =>
                         {
-                            as_keyword(path.res).map(|(_, prim)| (id.def_id.to_def_id(), prim))
+                            as_keyword(path.res.expect_non_local())
+                                .map(|(_, prim)| (id.def_id.to_def_id(), prim))
                         }
                         _ => None,
                     }
@@ -274,7 +275,7 @@ impl ExternalCrate {
         // Also note that this does not attempt to deal with modules tagged
         // duplicately for the same primitive. This is handled later on when
         // rendering by delegating everything to a hash map.
-        let as_primitive = |res: Res| {
+        let as_primitive = |res: Res<!>| {
             if let Res::Def(DefKind::Mod, def_id) = res {
                 let attrs = tcx.get_attrs(def_id);
                 let mut prim = None;
@@ -309,7 +310,7 @@ impl ExternalCrate {
                         hir::ItemKind::Use(ref path, hir::UseKind::Single)
                             if item.vis.node.is_pub() =>
                         {
-                            as_primitive(path.res).map(|(_, prim)| {
+                            as_primitive(path.res.expect_non_local()).map(|(_, prim)| {
                                 // Pretend the primitive is local.
                                 (id.def_id.to_def_id(), prim)
                             })
@@ -1110,7 +1111,7 @@ impl GenericBound {
     crate fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
         let did = cx.tcx.require_lang_item(LangItem::Sized, None);
         let empty = cx.tcx.intern_substs(&[]);
-        let path = external_path(cx, cx.tcx.item_name(did), Some(did), false, vec![], empty);
+        let path = external_path(cx, did, false, vec![], empty);
         inline::record_extern_fqn(cx, did, ItemType::Trait);
         GenericBound::TraitBound(
             PolyTrait {
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index de2cd60d2ed..b0021d1234c 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -29,10 +29,6 @@ crate fn krate(cx: &mut DocContext<'_>) -> Crate {
     let krate = cx.tcx.hir().krate();
     let module = crate::visit_ast::RustdocVisitor::new(cx).visit(krate);
 
-    cx.cache.deref_trait_did = cx.tcx.lang_items().deref_trait();
-    cx.cache.deref_mut_trait_did = cx.tcx.lang_items().deref_mut_trait();
-    cx.cache.owned_box_did = cx.tcx.lang_items().owned_box();
-
     let mut externs = Vec::new();
     for &cnum in cx.tcx.crates(()).iter() {
         externs.push(ExternalCrate { crate_num: cnum });
@@ -97,7 +93,7 @@ crate fn krate(cx: &mut DocContext<'_>) -> Crate {
 
 fn external_generic_args(
     cx: &mut DocContext<'_>,
-    trait_did: Option<DefId>,
+    did: DefId,
     has_self: bool,
     bindings: Vec<TypeBinding>,
     substs: SubstsRef<'_>,
@@ -125,42 +121,38 @@ fn external_generic_args(
         })
         .collect();
 
-    match trait_did {
-        // Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C
-        Some(did) if cx.tcx.fn_trait_kind_from_lang_item(did).is_some() => {
-            assert!(ty_kind.is_some());
-            let inputs = match ty_kind {
-                Some(ty::Tuple(ref tys)) => tys.iter().map(|t| t.expect_ty().clean(cx)).collect(),
-                _ => return GenericArgs::AngleBracketed { args, bindings },
-            };
-            let output = None;
-            // FIXME(#20299) return type comes from a projection now
-            // match types[1].kind {
-            //     ty::Tuple(ref v) if v.is_empty() => None, // -> ()
-            //     _ => Some(types[1].clean(cx))
-            // };
-            GenericArgs::Parenthesized { inputs, output }
-        }
-        _ => GenericArgs::AngleBracketed { args, bindings },
+    if cx.tcx.fn_trait_kind_from_lang_item(did).is_some() {
+        let inputs = match ty_kind.unwrap() {
+            ty::Tuple(tys) => tys.iter().map(|t| t.expect_ty().clean(cx)).collect(),
+            _ => return GenericArgs::AngleBracketed { args, bindings },
+        };
+        let output = None;
+        // FIXME(#20299) return type comes from a projection now
+        // match types[1].kind {
+        //     ty::Tuple(ref v) if v.is_empty() => None, // -> ()
+        //     _ => Some(types[1].clean(cx))
+        // };
+        GenericArgs::Parenthesized { inputs, output }
+    } else {
+        GenericArgs::AngleBracketed { args, bindings }
     }
 }
 
-// trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar
-// from Fn<(A, B,), C> to Fn(A, B) -> C
 pub(super) fn external_path(
     cx: &mut DocContext<'_>,
-    name: Symbol,
-    trait_did: Option<DefId>,
+    did: DefId,
     has_self: bool,
     bindings: Vec<TypeBinding>,
     substs: SubstsRef<'_>,
 ) -> Path {
+    let def_kind = cx.tcx.def_kind(did);
+    let name = cx.tcx.item_name(did);
     Path {
         global: false,
-        res: Res::Err,
+        res: Res::Def(def_kind, did),
         segments: vec![PathSegment {
             name,
-            args: external_generic_args(cx, trait_did, has_self, bindings, substs),
+            args: external_generic_args(cx, did, has_self, bindings, substs),
         }],
     }
 }
@@ -409,8 +401,8 @@ crate fn print_const_expr(tcx: TyCtxt<'_>, body: hir::BodyId) -> String {
 }
 
 /// Given a type Path, resolve it to a Type using the TyCtxt
-crate fn resolve_type(cx: &mut DocContext<'_>, path: Path, id: hir::HirId) -> Type {
-    debug!("resolve_type({:?},{:?})", path, id);
+crate fn resolve_type(cx: &mut DocContext<'_>, path: Path) -> Type {
+    debug!("resolve_type({:?})", path);
 
     let is_generic = match path.res {
         Res::PrimTy(p) => return Primitive(PrimitiveType::from(p)),
@@ -418,7 +410,7 @@ crate fn resolve_type(cx: &mut DocContext<'_>, path: Path, id: hir::HirId) -> Ty
             return Generic(kw::SelfUpper);
         }
         Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => {
-            return Generic(Symbol::intern(&path.whole_name()));
+            return Generic(path.segments[0].name);
         }
         Res::SelfTy(..) | Res::Def(DefKind::TyParam | DefKind::AssocTy, _) => true,
         _ => false,
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index 66fd0d9262d..bcfcc3d7039 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -98,9 +98,6 @@ crate struct Cache {
     stripped_mod: bool,
 
     crate search_index: Vec<IndexItem>,
-    crate deref_trait_did: Option<DefId>,
-    crate deref_mut_trait_did: Option<DefId>,
-    crate owned_box_did: Option<DefId>,
 
     // In rare case where a structure is defined in one module but implemented
     // in another, if the implementing module is parsed before defining module,
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index f71660c4b2a..1f27357f6c6 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -51,6 +51,7 @@ use rustc_hir::def::CtorKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::Mutability;
 use rustc_middle::middle::stability;
+use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::{kw, sym, Symbol};
 use serde::ser::SerializeSeq;
 use serde::{Serialize, Serializer};
@@ -1067,13 +1068,13 @@ fn render_assoc_items(
         return;
     }
     if !traits.is_empty() {
-        let deref_impl = traits
-            .iter()
-            .find(|t| t.inner_impl().trait_.def_id_full(cache) == cache.deref_trait_did);
+        let deref_impl = traits.iter().find(|t| {
+            t.inner_impl().trait_.def_id_full(cache) == cx.tcx().lang_items().deref_trait()
+        });
         if let Some(impl_) = deref_impl {
-            let has_deref_mut = traits
-                .iter()
-                .any(|t| t.inner_impl().trait_.def_id_full(cache) == cache.deref_mut_trait_did);
+            let has_deref_mut = traits.iter().any(|t| {
+                t.inner_impl().trait_.def_id_full(cache) == cx.tcx().lang_items().deref_mut_trait()
+            });
             render_deref_methods(w, cx, impl_, containing_item, has_deref_mut);
         }
         let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) =
@@ -1163,7 +1164,7 @@ fn render_deref_methods(
     }
 }
 
-fn should_render_item(item: &clean::Item, deref_mut_: bool, cache: &Cache) -> bool {
+fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> bool {
     let self_type_opt = match *item.kind {
         clean::MethodItem(ref method, _) => method.decl.self_type(),
         clean::TyMethodItem(ref method) => method.decl.self_type(),
@@ -1177,7 +1178,7 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, cache: &Cache) -> bo
                 (mutability == Mutability::Mut, false, false)
             }
             SelfTy::SelfExplicit(clean::ResolvedPath { did, .. }) => {
-                (false, Some(did) == cache.owned_box_did, false)
+                (false, Some(did) == tcx.lang_items().owned_box(), false)
             }
             SelfTy::SelfValue => (false, false, true),
             _ => (false, false, false),
@@ -1300,7 +1301,7 @@ fn render_impl(
             && match render_mode {
                 RenderMode::Normal => true,
                 RenderMode::ForDeref { mut_: deref_mut_ } => {
-                    should_render_item(&item, deref_mut_, cx.cache())
+                    should_render_item(&item, deref_mut_, cx.tcx())
                 }
             };
 
@@ -1798,13 +1799,13 @@ fn get_methods(
     for_deref: bool,
     used_links: &mut FxHashSet<String>,
     deref_mut: bool,
-    cache: &Cache,
+    tcx: TyCtxt<'_>,
 ) -> Vec<String> {
     i.items
         .iter()
         .filter_map(|item| match item.name {
             Some(ref name) if !name.is_empty() && item.is_method() => {
-                if !for_deref || should_render_item(item, deref_mut, cache) {
+                if !for_deref || should_render_item(item, deref_mut, tcx) {
                     Some(format!(
                         "<a href=\"#{}\">{}</a>",
                         get_next_url(used_links, format!("method.{}", name)),
@@ -1866,7 +1867,9 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
             let mut ret = v
                 .iter()
                 .filter(|i| i.inner_impl().trait_.is_none())
-                .flat_map(move |i| get_methods(i.inner_impl(), false, used_links_bor, false, cache))
+                .flat_map(move |i| {
+                    get_methods(i.inner_impl(), false, used_links_bor, false, cx.tcx())
+                })
                 .collect::<Vec<_>>();
             if !ret.is_empty() {
                 // We want links' order to be reproducible so we don't use unstable sort.
@@ -1884,11 +1887,9 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
         }
 
         if v.iter().any(|i| i.inner_impl().trait_.is_some()) {
-            if let Some(impl_) = v
-                .iter()
-                .filter(|i| i.inner_impl().trait_.is_some())
-                .find(|i| i.inner_impl().trait_.def_id_full(cache) == cache.deref_trait_did)
-            {
+            if let Some(impl_) = v.iter().filter(|i| i.inner_impl().trait_.is_some()).find(|i| {
+                i.inner_impl().trait_.def_id_full(cache) == cx.tcx().lang_items().deref_trait()
+            }) {
                 sidebar_deref_methods(cx, out, impl_, v);
             }
 
@@ -1986,10 +1987,9 @@ fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &V
                 }
             }
         }
-        let deref_mut = v
-            .iter()
-            .filter(|i| i.inner_impl().trait_.is_some())
-            .any(|i| i.inner_impl().trait_.def_id_full(c) == c.deref_mut_trait_did);
+        let deref_mut = v.iter().filter(|i| i.inner_impl().trait_.is_some()).any(|i| {
+            i.inner_impl().trait_.def_id_full(c) == cx.tcx().lang_items().deref_mut_trait()
+        });
         let inner_impl = target
             .def_id_full(c)
             .or_else(|| {
@@ -2002,7 +2002,9 @@ fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &V
             let mut ret = impls
                 .iter()
                 .filter(|i| i.inner_impl().trait_.is_none())
-                .flat_map(|i| get_methods(i.inner_impl(), true, &mut used_links, deref_mut, c))
+                .flat_map(|i| {
+                    get_methods(i.inner_impl(), true, &mut used_links, deref_mut, cx.tcx())
+                })
                 .collect::<Vec<_>>();
             if !ret.is_empty() {
                 write!(
diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs
index 3e06b417314..3e98ba08fb9 100644
--- a/src/librustdoc/visit_lib.rs
+++ b/src/librustdoc/visit_lib.rs
@@ -67,7 +67,7 @@ impl<'a, 'tcx> LibEmbargoVisitor<'a, 'tcx> {
         }
     }
 
-    fn visit_item(&mut self, res: Res) {
+    fn visit_item(&mut self, res: Res<!>) {
         let def_id = res.def_id();
         let vis = self.tcx.visibility(def_id);
         let inherited_item_level = if vis == Visibility::Public { self.prev_level } else { None };
diff --git a/src/test/rustdoc/synthetic_auto/no-redundancy.rs b/src/test/rustdoc/synthetic_auto/no-redundancy.rs
index f727c9a47f2..16ab876e829 100644
--- a/src/test/rustdoc/synthetic_auto/no-redundancy.rs
+++ b/src/test/rustdoc/synthetic_auto/no-redundancy.rs
@@ -10,7 +10,7 @@ where
 
 // @has no_redundancy/struct.Outer.html
 // @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' \
-// "impl<T> Send for Outer<T> where T: Copy + Send"
+// "impl<T> Send for Outer<T> where T: Send + Copy"
 pub struct Outer<T> {
     inner_field: Inner<T>,
 }
diff --git a/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs b/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs
new file mode 100644
index 00000000000..916d60c0e0d
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.rs
@@ -0,0 +1,11 @@
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+fn foo<const N: u8>(a: [(); N as usize]) {
+    bar::<{ N as usize as usize }>();
+    //~^ error: unconstrained generic constant
+}
+
+fn bar<const N: usize>() {}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.stderr b/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.stderr
new file mode 100644
index 00000000000..d48b639dbde
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/abstract-consts-as-cast-5.stderr
@@ -0,0 +1,10 @@
+error: unconstrained generic constant
+  --> $DIR/abstract-consts-as-cast-5.rs:5:11
+   |
+LL |     bar::<{ N as usize as usize }>();
+   |           ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try adding a `where` bound using this expression: `where [(); { N as usize as usize }]:`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr b/src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr
index deb6f3bd12c..9b3c32a9397 100644
--- a/src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr
+++ b/src/test/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.full.stderr
@@ -10,7 +10,7 @@ error: overly complex generic constant
   --> $DIR/array-size-in-generic-struct-param.rs:19:15
    |
 LL |     arr: [u8; CFG.arr_size],
-   |               ^^^^^^^^^^^^ unsupported projection
+   |               ^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future
    |
    = help: consider moving this anonymous constant into a `const` function
 
diff --git a/src/test/ui/const-generics/generic_const_exprs/closures.stderr b/src/test/ui/const-generics/generic_const_exprs/closures.stderr
index 9f0b7252e83..95dae4ecc04 100644
--- a/src/test/ui/const-generics/generic_const_exprs/closures.stderr
+++ b/src/test/ui/const-generics/generic_const_exprs/closures.stderr
@@ -4,7 +4,7 @@ error: overly complex generic constant
 LL | fn test<const N: usize>() -> [u8; N + (|| 42)()] {}
    |                                   ^^^^-------^^
    |                                       |
-   |                                       unsupported rvalue
+   |                                       unsupported operation in generic constant, this may be supported in the future
    |
    = help: consider moving this anonymous constant into a `const` function
 
diff --git a/src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr b/src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr
index 5749defb3e1..c9f84799522 100644
--- a/src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr
+++ b/src/test/ui/const-generics/generic_const_exprs/let-bindings.stderr
@@ -2,9 +2,7 @@ error: overly complex generic constant
   --> $DIR/let-bindings.rs:6:68
    |
 LL | fn test<const N: usize>() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default {
-   |                                                                    ^^^^^^-^^^^^^^^^^^^^
-   |                                                                          |
-   |                                                                          unsupported statement
+   |                                                                    ^^^^^^^^^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future
    |
    = help: consider moving this anonymous constant into a `const` function
 
@@ -12,9 +10,7 @@ error: overly complex generic constant
   --> $DIR/let-bindings.rs:6:35
    |
 LL | fn test<const N: usize>() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default {
-   |                                   ^^^^^^-^^^^^^^^^^^^^
-   |                                         |
-   |                                         unsupported statement
+   |                                   ^^^^^^^^^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future
    |
    = help: consider moving this anonymous constant into a `const` function
 
diff --git a/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs b/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs
new file mode 100644
index 00000000000..c0404d35b08
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.rs
@@ -0,0 +1,35 @@
+#![feature(generic_const_exprs, adt_const_params, const_trait_impl)]
+#![allow(incomplete_features)]
+
+// test `N + N` unifies with explicit function calls for non-builtin-types
+#[derive(PartialEq, Eq)]
+struct Foo(u8);
+
+impl const std::ops::Add for Foo {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self::Output {
+        self
+    }
+}
+
+struct Evaluatable<const N: Foo>;
+
+fn foo<const N: Foo>(a: Evaluatable<{ N + N }>) {
+    bar::<{ std::ops::Add::add(N, N) }>();
+}
+
+fn bar<const N: Foo>() {}
+
+// test that `N + N` unifies with explicit function calls for builin-types
+struct Evaluatable2<const N: usize>;
+
+fn foo2<const N: usize>(a: Evaluatable2<{ N + N }>) {
+    bar2::<{ std::ops::Add::add(N, N) }>();
+    //~^ error: unconstrained generic constant
+    // FIXME(generic_const_exprs) make this not an error
+}
+
+fn bar2<const N: usize>() {}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr b/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr
new file mode 100644
index 00000000000..d18c7916f5f
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/unify-op-with-fn-call.stderr
@@ -0,0 +1,10 @@
+error: unconstrained generic constant
+  --> $DIR/unify-op-with-fn-call.rs:28:12
+   |
+LL |     bar2::<{ std::ops::Add::add(N, N) }>();
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try adding a `where` bound using this expression: `where [(); { std::ops::Add::add(N, N) }]:`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr b/src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr
index 1687dbbcbe3..3da91b19a5e 100644
--- a/src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr
+++ b/src/test/ui/const-generics/generic_const_exprs/unused_expr.stderr
@@ -2,9 +2,7 @@ error: overly complex generic constant
   --> $DIR/unused_expr.rs:4:34
    |
 LL | fn add<const N: usize>() -> [u8; { N + 1; 5 }] {
-   |                                  ^^-----^^^^^
-   |                                    |
-   |                                    dead code
+   |                                  ^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future
    |
    = help: consider moving this anonymous constant into a `const` function
 
@@ -12,9 +10,7 @@ error: overly complex generic constant
   --> $DIR/unused_expr.rs:9:34
    |
 LL | fn div<const N: usize>() -> [u8; { N / 1; 5 }] {
-   |                                  ^^-----^^^^^
-   |                                    |
-   |                                    dead code
+   |                                  ^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future
    |
    = help: consider moving this anonymous constant into a `const` function
 
@@ -22,9 +18,7 @@ error: overly complex generic constant
   --> $DIR/unused_expr.rs:16:38
    |
 LL | fn fn_call<const N: usize>() -> [u8; { foo(N); 5 }] {
-   |                                      ^^------^^^^^
-   |                                        |
-   |                                        dead code
+   |                                      ^^^^^^^^^^^^^ unsupported operation in generic constant, this may be supported in the future
    |
    = help: consider moving this anonymous constant into a `const` function
 
diff --git a/src/test/ui/const-generics/issues/issue-67375.full.stderr b/src/test/ui/const-generics/issues/issue-67375.full.stderr
index 5386ef56a24..d7b52063dc4 100644
--- a/src/test/ui/const-generics/issues/issue-67375.full.stderr
+++ b/src/test/ui/const-generics/issues/issue-67375.full.stderr
@@ -2,9 +2,9 @@ error: overly complex generic constant
   --> $DIR/issue-67375.rs:7:17
    |
 LL |     inner: [(); { [|_: &T| {}; 0].len() }],
-   |                 ^^^----------^^^^^^^^^^^^
-   |                    |
-   |                    unsupported rvalue
+   |                 ^^---------------^^^^^^^^
+   |                   |
+   |                   unsupported operation in generic constant
    |
    = help: consider moving this anonymous constant into a `const` function
 
diff --git a/src/test/ui/const-generics/issues/issue-67945-2.full.stderr b/src/test/ui/const-generics/issues/issue-67945-2.full.stderr
index 118cf447c01..fe0351a8292 100644
--- a/src/test/ui/const-generics/issues/issue-67945-2.full.stderr
+++ b/src/test/ui/const-generics/issues/issue-67945-2.full.stderr
@@ -5,11 +5,10 @@ LL |       A: [(); {
    |  _____________^
 LL | |
 LL | |         let x: Option<Box<Self>> = None;
-   | |                                    ---- unsupported rvalue
 LL | |
 LL | |         0
 LL | |     }],
-   | |_____^
+   | |_____^ unsupported operation in generic constant, this may be supported in the future
    |
    = help: consider moving this anonymous constant into a `const` function
 
diff --git a/src/test/ui/generic-associated-types/impl_bounds.rs b/src/test/ui/generic-associated-types/impl_bounds.rs
index 01edad00a89..27c135cb7cf 100644
--- a/src/test/ui/generic-associated-types/impl_bounds.rs
+++ b/src/test/ui/generic-associated-types/impl_bounds.rs
@@ -15,7 +15,7 @@ impl<T> Foo for Fooy<T> {
     type A<'a> where Self: 'static = (&'a ());
     //~^ ERROR the parameter type `T` may not live long enough
     type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
-    //~^ ERROR lifetime bound not satisfied
+    //~^ ERROR `impl` associated type
     //~| ERROR lifetime bound not satisfied
     type C where Self: Copy = String;
     //~^ ERROR the trait bound `T: Copy` is not satisfied
diff --git a/src/test/ui/generic-associated-types/impl_bounds.stderr b/src/test/ui/generic-associated-types/impl_bounds.stderr
index 8cf923ca3ac..73415e0faac 100644
--- a/src/test/ui/generic-associated-types/impl_bounds.stderr
+++ b/src/test/ui/generic-associated-types/impl_bounds.stderr
@@ -5,24 +5,16 @@ LL |     type A<'a> where Self: 'static = (&'a ());
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider adding an explicit lifetime bound `T: 'static`...
-   = note: ...so that the type `Fooy<T>` will meet its required lifetime bounds
+   = note: ...so that the definition in impl matches the definition from the trait
 
-error[E0478]: lifetime bound not satisfied
+error: `impl` associated type signature for `B` doesn't match `trait` associated type signature
   --> $DIR/impl_bounds.rs:17:5
    |
+LL |     type B<'a, 'b> where 'a: 'b;
+   |     ---------------------------- expected
+...
 LL |     type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: lifetime parameter instantiated with the lifetime `'b` as defined on the associated item at 17:16
-  --> $DIR/impl_bounds.rs:17:16
-   |
-LL |     type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
-   |                ^^
-note: but lifetime parameter must outlive the lifetime `'a` as defined on the associated item at 17:12
-  --> $DIR/impl_bounds.rs:17:12
-   |
-LL |     type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
-   |            ^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found
 
 error[E0478]: lifetime bound not satisfied
   --> $DIR/impl_bounds.rs:17:5
diff --git a/src/test/ui/generic-associated-types/issue-86787.stderr b/src/test/ui/generic-associated-types/issue-86787.stderr
index 04cd84b0801..e1ff7729211 100644
--- a/src/test/ui/generic-associated-types/issue-86787.stderr
+++ b/src/test/ui/generic-associated-types/issue-86787.stderr
@@ -9,7 +9,7 @@ LL | |     <Left as HasChildrenOf>::T: 'a,
 LL | |     <Right as HasChildrenOf>::T: 'a
    | |                                    - help: consider adding a where clause: `, <Left as HasChildrenOf>::T: 'a`
 LL | |     = Either<&'a Left::T, &'a Right::T>;
-   | |________________________________________^ ...so that the type `<Left as HasChildrenOf>::T` will meet its required lifetime bounds
+   | |________________________________________^ ...so that the definition in impl matches the definition from the trait
 
 error[E0309]: the associated type `<Right as HasChildrenOf>::T` may not live long enough
   --> $DIR/issue-86787.rs:23:5
@@ -22,7 +22,7 @@ LL | |     <Left as HasChildrenOf>::T: 'a,
 LL | |     <Right as HasChildrenOf>::T: 'a
    | |                                    - help: consider adding a where clause: `, <Right as HasChildrenOf>::T: 'a`
 LL | |     = Either<&'a Left::T, &'a Right::T>;
-   | |________________________________________^ ...so that the type `<Right as HasChildrenOf>::T` will meet its required lifetime bounds
+   | |________________________________________^ ...so that the definition in impl matches the definition from the trait
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs
new file mode 100644
index 00000000000..ad9f2e3e4ec
--- /dev/null
+++ b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.rs
@@ -0,0 +1,13 @@
+// check-fail
+
+#![feature(generic_associated_types)]
+
+trait Foo {
+    type Assoc<'a, 'b>;
+}
+impl Foo for () {
+    type Assoc<'a, 'b> where 'a: 'b = ();
+    //~^ `impl` associated type
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr
new file mode 100644
index 00000000000..0e183c8d69a
--- /dev/null
+++ b/src/test/ui/generic-associated-types/missing-where-clause-on-trait.stderr
@@ -0,0 +1,11 @@
+error: `impl` associated type signature for `Assoc` doesn't match `trait` associated type signature
+  --> $DIR/missing-where-clause-on-trait.rs:9:5
+   |
+LL |     type Assoc<'a, 'b>;
+   |     ------------------- expected
+...
+LL |     type Assoc<'a, 'b> where 'a: 'b = ();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index da259511fe0..3a94f472983 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -520,7 +520,7 @@ pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Res {
             }
         };
     }
-    fn item_child_by_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, name: &str) -> Option<&'tcx Export<HirId>> {
+    fn item_child_by_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, name: &str) -> Option<&'tcx Export> {
         tcx.item_children(def_id)
             .iter()
             .find(|item| item.ident.name.as_str() == name)
@@ -557,7 +557,7 @@ pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Res {
                 None
             }
         });
-    try_res!(last).res
+    try_res!(last).res.expect_non_local()
 }
 
 /// Convenience function to get the `DefId` of a trait by path.