about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-03-09 17:18:20 +0100
committerGitHub <noreply@github.com>2019-03-09 17:18:20 +0100
commitf32d62e5ae28c8398630117a2aea4a5cf5fb13f1 (patch)
tree111900ad79035e738bce4a1d56296677ad778fc8
parent3f872b209ba573e28053885e9fc4a86581fb82ea (diff)
parent7985c6f8ecf680dcc960bb2ccc0c787274a449de (diff)
downloadrust-f32d62e5ae28c8398630117a2aea4a5cf5fb13f1.tar.gz
rust-f32d62e5ae28c8398630117a2aea4a5cf5fb13f1.zip
Rollup merge of #58679 - Zoxc:passes-refactor, r=michaelwoerister
Refactor passes and pass execution to be more parallel

For `syntex_syntax` (with 16 threads and 8 cores):
- Cuts `misc checking 1` from `0.096s` to `0.08325s`.
- Cuts `misc checking 2` from `0.3575s` to `0.2545s`.
- Cuts `misc checking 3` from `0.34625s` to `0.21375s`.
- Cuts `wf checking` from `0.3085s` to `0.05025s`.

Reduces overall execution time for `syntex_syntax` (with 8 threads and cores) from `4.92s` to `4.34s`.

Subsumes https://github.com/rust-lang/rust/pull/58494
Blocked on https://github.com/rust-lang/rust/pull/58250

r? @michaelwoerister
-rw-r--r--src/librustc/dep_graph/dep_node.rs1
-rw-r--r--src/librustc/hir/check_attr.rs6
-rw-r--r--src/librustc/hir/mod.rs8
-rw-r--r--src/librustc/middle/intrinsicck.rs6
-rw-r--r--src/librustc/middle/liveness.rs6
-rw-r--r--src/librustc/middle/stability.rs6
-rw-r--r--src/librustc/ty/query/config.rs6
-rw-r--r--src/librustc/ty/query/mod.rs3
-rw-r--r--src/librustc/ty/query/plumbing.rs1
-rw-r--r--src/librustc_data_structures/sync.rs61
-rw-r--r--src/librustc_interface/passes.rs98
-rw-r--r--src/librustc_mir/hair/pattern/check_match.rs7
-rw-r--r--src/librustc_mir/hair/pattern/mod.rs1
-rw-r--r--src/librustc_mir/lib.rs1
-rw-r--r--src/librustc_passes/loops.rs6
-rw-r--r--src/librustc_passes/rvalue_promotion.rs7
-rw-r--r--src/librustc_privacy/lib.rs78
-rw-r--r--src/librustc_typeck/check/mod.rs14
-rw-r--r--src/librustc_typeck/check/wfcheck.rs10
-rw-r--r--src/librustc_typeck/coherence/mod.rs4
-rw-r--r--src/librustc_typeck/collect.rs6
-rw-r--r--src/librustc_typeck/lib.rs17
-rw-r--r--src/test/ui/issues/issue-20413.rs1
-rw-r--r--src/test/ui/issues/issue-20413.stderr82
-rw-r--r--src/test/ui/issues/issue-21946.rs1
-rw-r--r--src/test/ui/issues/issue-21946.stderr8
-rw-r--r--src/test/ui/issues/issue-23122-1.rs1
-rw-r--r--src/test/ui/issues/issue-23122-1.stderr8
-rw-r--r--src/test/ui/issues/issue-23122-2.rs1
-rw-r--r--src/test/ui/issues/issue-23122-2.stderr11
-rw-r--r--src/test/ui/privacy/private-inferred-type.stderr36
31 files changed, 305 insertions, 197 deletions
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index c607eb5906e..41a4a803100 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -456,6 +456,7 @@ define_dep_nodes!( <'tcx>
     [eval_always] CoherenceInherentImplOverlapCheck,
     [] CoherenceCheckTrait(DefId),
     [eval_always] PrivacyAccessLevels(CrateNum),
+    [eval_always] CheckPrivateInPublic(CrateNum),
     [eval_always] Analysis(CrateNum),
 
     // Represents the MIR for a fn; also used as the task node for
diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs
index 8b304007a35..86f7e149964 100644
--- a/src/librustc/hir/check_attr.rs
+++ b/src/librustc/hir/check_attr.rs
@@ -344,12 +344,6 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckAttrVisitor<'a, 'tcx> {
     }
 }
 
-pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    for &module in tcx.hir().krate().modules.keys() {
-        tcx.ensure().check_mod_attrs(tcx.hir().local_def_id(module));
-    }
-}
-
 fn is_c_like_enum(item: &hir::Item) -> bool {
     if let hir::ItemKind::Enum(ref def, _) = item.node {
         for variant in &def.variants {
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 4fb8b7168b8..e47bc3d1c25 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -30,7 +30,7 @@ use syntax::util::parser::ExprPrecedence;
 use crate::ty::AdtKind;
 use crate::ty::query::Providers;
 
-use rustc_data_structures::sync::{ParallelIterator, par_iter, Send, Sync};
+use rustc_data_structures::sync::{par_for_each_in, Send, Sync};
 use rustc_data_structures::thin_vec::ThinVec;
 use rustc_macros::HashStable;
 
@@ -779,15 +779,15 @@ impl Crate {
         where V: itemlikevisit::ParItemLikeVisitor<'hir> + Sync + Send
     {
         parallel!({
-            par_iter(&self.items).for_each(|(_, item)| {
+            par_for_each_in(&self.items, |(_, item)| {
                 visitor.visit_item(item);
             });
         }, {
-            par_iter(&self.trait_items).for_each(|(_, trait_item)| {
+            par_for_each_in(&self.trait_items, |(_, trait_item)| {
                 visitor.visit_trait_item(trait_item);
             });
         }, {
-            par_iter(&self.impl_items).for_each(|(_, impl_item)| {
+            par_for_each_in(&self.impl_items, |(_, impl_item)| {
                 visitor.visit_impl_item(impl_item);
             });
         });
diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs
index ce20ca39533..c4071e9f354 100644
--- a/src/librustc/middle/intrinsicck.rs
+++ b/src/librustc/middle/intrinsicck.rs
@@ -10,12 +10,6 @@ use syntax_pos::Span;
 use crate::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use crate::hir;
 
-pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    for &module in tcx.hir().krate().modules.keys() {
-        tcx.ensure().check_mod_intrinsics(tcx.hir().local_def_id(module));
-    }
-}
-
 fn check_mod_intrinsics<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, module_def_id: DefId) {
     tcx.hir().visit_item_likes_in_module(
         module_def_id,
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 709e0513202..f5a95d7004b 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -185,12 +185,6 @@ fn check_mod_liveness<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, module_def_id: DefId) {
     tcx.hir().visit_item_likes_in_module(module_def_id, &mut IrMaps::new(tcx).as_deep_visitor());
 }
 
-pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    for &module in tcx.hir().krate().modules.keys() {
-        tcx.ensure().check_mod_liveness(tcx.hir().local_def_id(module));
-    }
-}
-
 pub fn provide(providers: &mut Providers<'_>) {
     *providers = Providers {
         check_mod_liveness,
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index aa239244861..1677384059e 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -456,12 +456,6 @@ impl<'a, 'tcx> Index<'tcx> {
     }
 }
 
-pub fn check_unstable_api_usage<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    for &module in tcx.hir().krate().modules.keys() {
-        tcx.ensure().check_mod_unstable_api_usage(tcx.hir().local_def_id(module));
-    }
-}
-
 /// Cross-references the feature names of unstable APIs with enabled
 /// features and possibly prints errors.
 fn check_mod_unstable_api_usage<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, module_def_id: DefId) {
diff --git a/src/librustc/ty/query/config.rs b/src/librustc/ty/query/config.rs
index 49aa6b9e956..6488c0db42b 100644
--- a/src/librustc/ty/query/config.rs
+++ b/src/librustc/ty/query/config.rs
@@ -369,6 +369,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::privacy_access_levels<'tcx> {
     }
 }
 
+impl<'tcx> QueryDescription<'tcx> for queries::check_private_in_public<'tcx> {
+    fn describe(_: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> {
+        "checking for private elements in public interfaces".into()
+    }
+}
+
 impl<'tcx> QueryDescription<'tcx> for queries::typeck_item_bodies<'tcx> {
     fn describe(_: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> {
         "type-checking all item bodies".into()
diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs
index 197b9a71b0a..8804ed22264 100644
--- a/src/librustc/ty/query/mod.rs
+++ b/src/librustc/ty/query/mod.rs
@@ -350,8 +350,9 @@ define_queries! { <'tcx>
         [] fn check_match: CheckMatch(DefId)
             -> Result<(), ErrorReported>,
 
-        /// Performs the privacy check and computes "access levels".
+        /// Performs part of the privacy check and computes "access levels".
         [] fn privacy_access_levels: PrivacyAccessLevels(CrateNum) -> Lrc<AccessLevels>,
+        [] fn check_private_in_public: CheckPrivateInPublic(CrateNum) -> (),
     },
 
     Other {
diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs
index ebaa31d703f..e3276ba0bea 100644
--- a/src/librustc/ty/query/plumbing.rs
+++ b/src/librustc/ty/query/plumbing.rs
@@ -1251,6 +1251,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
             force!(crate_inherent_impls_overlap_check, LOCAL_CRATE)
         },
         DepKind::PrivacyAccessLevels => { force!(privacy_access_levels, LOCAL_CRATE); }
+        DepKind::CheckPrivateInPublic => { force!(check_private_in_public, LOCAL_CRATE); }
         DepKind::MirBuilt => { force!(mir_built, def_id!()); }
         DepKind::MirConstQualif => { force!(mir_const_qualif, def_id!()); }
         DepKind::MirConst => { force!(mir_const, def_id!()); }
diff --git a/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs
index ba1f6eb56fe..73247c1469e 100644
--- a/src/librustc_data_structures/sync.rs
+++ b/src/librustc_data_structures/sync.rs
@@ -65,6 +65,7 @@ cfg_if! {
         }
 
         use std::ops::Add;
+        use std::panic::{resume_unwind, catch_unwind, AssertUnwindSafe};
 
         #[derive(Debug)]
         pub struct Atomic<T: Copy>(Cell<T>);
@@ -130,7 +131,21 @@ cfg_if! {
         #[macro_export]
         macro_rules! parallel {
             ($($blocks:tt),*) => {
-                $($blocks)*;
+                // We catch panics here ensuring that all the blocks execute.
+                // This makes behavior consistent with the parallel compiler.
+                let mut panic = None;
+                $(
+                    if let Err(p) = ::std::panic::catch_unwind(
+                        ::std::panic::AssertUnwindSafe(|| $blocks)
+                    ) {
+                        if panic.is_none() {
+                            panic = Some(p);
+                        }
+                    }
+                )*
+                if let Some(panic) = panic {
+                    ::std::panic::resume_unwind(panic);
+                }
             }
         }
 
@@ -140,6 +155,26 @@ cfg_if! {
             t.into_iter()
         }
 
+        pub fn par_for_each_in<T: IntoIterator>(
+            t: T,
+            for_each:
+                impl Fn(<<T as IntoIterator>::IntoIter as Iterator>::Item) + Sync + Send
+        ) {
+            // We catch panics here ensuring that all the loop iterations execute.
+            // This makes behavior consistent with the parallel compiler.
+            let mut panic = None;
+            t.into_iter().for_each(|i| {
+                if let Err(p) = catch_unwind(AssertUnwindSafe(|| for_each(i))) {
+                    if panic.is_none() {
+                        panic = Some(p);
+                    }
+                }
+            });
+            if let Some(panic) = panic {
+                resume_unwind(panic);
+            }
+        }
+
         pub type MetadataRef = OwningRef<Box<dyn Erased>, [u8]>;
 
         pub use std::rc::Rc as Lrc;
@@ -278,23 +313,26 @@ cfg_if! {
         use std::thread;
         pub use rayon::{join, scope};
 
+        /// Runs a list of blocks in parallel. The first block is executed immediately on
+        /// the current thread. Use that for the longest running block.
         #[macro_export]
         macro_rules! parallel {
-            (impl [$($c:tt,)*] [$block:tt $(, $rest:tt)*]) => {
-                parallel!(impl [$block, $($c,)*] [$($rest),*])
+            (impl $fblock:tt [$($c:tt,)*] [$block:tt $(, $rest:tt)*]) => {
+                parallel!(impl $fblock [$block, $($c,)*] [$($rest),*])
             };
-            (impl [$($blocks:tt,)*] []) => {
+            (impl $fblock:tt [$($blocks:tt,)*] []) => {
                 ::rustc_data_structures::sync::scope(|s| {
                     $(
                         s.spawn(|_| $blocks);
                     )*
+                    $fblock;
                 })
             };
-            ($($blocks:tt),*) => {
-                // Reverse the order of the blocks since Rayon executes them in reverse order
+            ($fblock:tt, $($blocks:tt),*) => {
+                // Reverse the order of the later blocks since Rayon executes them in reverse order
                 // when using a single thread. This ensures the execution order matches that
                 // of a single threaded rustc
-                parallel!(impl [] [$($blocks),*]);
+                parallel!(impl $fblock [] [$($blocks),*]);
             };
         }
 
@@ -307,6 +345,15 @@ cfg_if! {
             t.into_par_iter()
         }
 
+        pub fn par_for_each_in<T: IntoParallelIterator>(
+            t: T,
+            for_each: impl Fn(
+                <<T as IntoParallelIterator>::Iter as ParallelIterator>::Item
+            ) + Sync + Send
+        ) {
+            t.into_par_iter().for_each(for_each)
+        }
+
         pub type MetadataRef = OwningRef<Box<dyn Erased + Send + Sync>, [u8]>;
 
         /// This makes locks panic if they are already held.
diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs
index 16ced695638..8277615b465 100644
--- a/src/librustc_interface/passes.rs
+++ b/src/librustc_interface/passes.rs
@@ -21,7 +21,7 @@ use rustc_borrowck as borrowck;
 use rustc_codegen_utils::codegen_backend::CodegenBackend;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::stable_hasher::StableHasher;
-use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::sync::{Lrc, ParallelIterator, par_iter};
 use rustc_incremental;
 use rustc_metadata::creader::CrateLoader;
 use rustc_metadata::cstore::{self, CStore};
@@ -191,51 +191,50 @@ fn analysis<'tcx>(
 
     let sess = tcx.sess;
 
-    parallel!({
-        time(sess, "looking for entry point", || {
-            middle::entry::find_entry_point(tcx)
-        });
+    time(sess, "misc checking 1", || {
+        parallel!({
+            time(sess, "looking for entry point", || {
+                middle::entry::find_entry_point(tcx)
+            });
 
-        time(sess, "looking for plugin registrar", || {
-            plugin::build::find_plugin_registrar(tcx)
-        });
+            time(sess, "looking for plugin registrar", || {
+                plugin::build::find_plugin_registrar(tcx)
+            });
 
-        time(sess, "looking for derive registrar", || {
-            proc_macro_decls::find(tcx)
-        });
-    }, {
-        time(sess, "loop checking", || loops::check_crate(tcx));
-    }, {
-        time(sess, "attribute checking", || {
-            hir::check_attr::check_crate(tcx)
-        });
-    }, {
-        time(sess, "stability checking", || {
-            stability::check_unstable_api_usage(tcx)
+            time(sess, "looking for derive registrar", || {
+                proc_macro_decls::find(tcx)
+            });
+        }, {
+            par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| {
+                tcx.ensure().check_mod_loops(tcx.hir().local_def_id(module));
+                tcx.ensure().check_mod_attrs(tcx.hir().local_def_id(module));
+                tcx.ensure().check_mod_unstable_api_usage(tcx.hir().local_def_id(module));
+            });
         });
     });
 
     // passes are timed inside typeck
     typeck::check_crate(tcx)?;
 
-    time(sess, "misc checking", || {
+    time(sess, "misc checking 2", || {
         parallel!({
-            time(sess, "rvalue promotion", || {
-                rvalue_promotion::check_crate(tcx)
-            });
-        }, {
-            time(sess, "intrinsic checking", || {
-                middle::intrinsicck::check_crate(tcx)
+            time(sess, "rvalue promotion + match checking", || {
+                tcx.par_body_owners(|def_id| {
+                    tcx.ensure().const_is_rvalue_promotable_to_static(def_id);
+                    tcx.ensure().check_match(def_id);
+                });
             });
         }, {
-            time(sess, "match checking", || mir::matchck_crate(tcx));
-        }, {
-            // this must run before MIR dump, because
-            // "not all control paths return a value" is reported here.
-            //
-            // maybe move the check to a MIR pass?
-            time(sess, "liveness checking", || {
-                middle::liveness::check_crate(tcx)
+            time(sess, "liveness checking + intrinsic checking", || {
+                par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| {
+                    // this must run before MIR dump, because
+                    // "not all control paths return a value" is reported here.
+                    //
+                    // maybe move the check to a MIR pass?
+                    tcx.ensure().check_mod_liveness(tcx.hir().local_def_id(module));
+
+                    tcx.ensure().check_mod_intrinsics(tcx.hir().local_def_id(module));
+                });
             });
         });
     });
@@ -276,19 +275,30 @@ fn analysis<'tcx>(
         return Err(ErrorReported);
     }
 
-    time(sess, "misc checking", || {
+    time(sess, "misc checking 3", || {
         parallel!({
-            time(sess, "privacy checking", || {
-                rustc_privacy::check_crate(tcx)
+            time(sess, "privacy access levels", || {
+                tcx.ensure().privacy_access_levels(LOCAL_CRATE);
             });
-        }, {
-            time(sess, "death checking", || middle::dead::check_crate(tcx));
-        },  {
-            time(sess, "unused lib feature checking", || {
-                stability::check_unused_or_stable_features(tcx)
+            parallel!({
+                time(sess, "private in public", || {
+                    tcx.ensure().check_private_in_public(LOCAL_CRATE);
+                });
+            }, {
+                time(sess, "death checking", || middle::dead::check_crate(tcx));
+            },  {
+                time(sess, "unused lib feature checking", || {
+                    stability::check_unused_or_stable_features(tcx)
+                });
+            }, {
+                time(sess, "lint checking", || lint::check_crate(tcx));
             });
         }, {
-            time(sess, "lint checking", || lint::check_crate(tcx));
+            time(sess, "privacy checking modules", || {
+                par_iter(&tcx.hir().krate().modules).for_each(|(&module, _)| {
+                    tcx.ensure().check_mod_privacy(tcx.hir().local_def_id(module));
+                });
+            });
         });
     });
 
diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs
index 9768706b37e..41babc1ad12 100644
--- a/src/librustc_mir/hair/pattern/check_match.rs
+++ b/src/librustc_mir/hair/pattern/check_match.rs
@@ -27,13 +27,6 @@ use std::slice;
 use syntax::ptr::P;
 use syntax_pos::{Span, DUMMY_SP, MultiSpan};
 
-pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    for def_id in tcx.body_owners() {
-        tcx.ensure().check_match(def_id);
-    }
-    tcx.sess.abort_if_errors();
-}
-
 pub(crate) fn check_match<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     def_id: DefId,
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index b17da609ab4..67d40197290 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -3,7 +3,6 @@
 mod _match;
 mod check_match;
 
-pub use self::check_match::check_crate;
 pub(crate) use self::check_match::check_match;
 
 use crate::const_eval::{const_field, const_variant_index};
diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs
index 06e79dc4e70..0b735b4b39c 100644
--- a/src/librustc_mir/lib.rs
+++ b/src/librustc_mir/lib.rs
@@ -54,7 +54,6 @@ pub mod interpret;
 pub mod monomorphize;
 pub mod const_eval;
 
-pub use hair::pattern::check_crate as matchck_crate;
 use rustc::ty::query::Providers;
 
 pub fn provide(providers: &mut Providers<'_>) {
diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs
index 2272ac97cdd..97bbb0adb2d 100644
--- a/src/librustc_passes/loops.rs
+++ b/src/librustc_passes/loops.rs
@@ -45,12 +45,6 @@ struct CheckLoopVisitor<'a, 'hir: 'a> {
     cx: Context,
 }
 
-pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    for &module in tcx.hir().krate().modules.keys() {
-        tcx.ensure().check_mod_loops(tcx.hir().local_def_id(module));
-    }
-}
-
 fn check_mod_loops<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, module_def_id: DefId) {
     tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckLoopVisitor {
         sess: &tcx.sess,
diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs
index 9de022a4021..6de98675a3d 100644
--- a/src/librustc_passes/rvalue_promotion.rs
+++ b/src/librustc_passes/rvalue_promotion.rs
@@ -39,13 +39,6 @@ pub fn provide(providers: &mut Providers<'_>) {
     };
 }
 
-pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    for &body_id in &tcx.hir().krate().body_ids {
-        let def_id = tcx.hir().body_owner_def_id(body_id);
-        tcx.const_is_rvalue_promotable_to_static(def_id);
-    }
-}
-
 fn const_is_rvalue_promotable_to_static<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                   def_id: DefId)
                                                   -> bool
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index d07e89209e7..52514a3ca97 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -1766,19 +1766,15 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
 pub fn provide(providers: &mut Providers<'_>) {
     *providers = Providers {
         privacy_access_levels,
+        check_private_in_public,
         check_mod_privacy,
         ..*providers
     };
 }
 
-pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Lrc<AccessLevels> {
-    tcx.privacy_access_levels(LOCAL_CRATE)
-}
-
 fn check_mod_privacy<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, module_def_id: DefId) {
     let empty_tables = ty::TypeckTables::empty(None);
 
-
     // Check privacy of names not checked in previous compilation stages.
     let mut visitor = NamePrivacyVisitor {
         tcx,
@@ -1809,18 +1805,6 @@ fn privacy_access_levels<'tcx>(
 ) -> Lrc<AccessLevels> {
     assert_eq!(krate, LOCAL_CRATE);
 
-    let krate = tcx.hir().krate();
-
-    for &module in krate.modules.keys() {
-        tcx.ensure().check_mod_privacy(tcx.hir().local_def_id(module));
-    }
-
-    let private_crates: FxHashSet<CrateNum> = tcx.sess.opts.extern_private.iter()
-        .flat_map(|c| {
-            tcx.crates().iter().find(|&&krate| &tcx.crate_name(krate) == c).cloned()
-        }).collect();
-
-
     // Build up a set of all exported items in the AST. This is a set of all
     // items which are reachable from external crates based on visibility.
     let mut visitor = EmbargoVisitor {
@@ -1830,7 +1814,7 @@ fn privacy_access_levels<'tcx>(
         changed: false,
     };
     loop {
-        intravisit::walk_crate(&mut visitor, krate);
+        intravisit::walk_crate(&mut visitor, tcx.hir().krate());
         if visitor.changed {
             visitor.changed = false;
         } else {
@@ -1839,36 +1823,46 @@ fn privacy_access_levels<'tcx>(
     }
     visitor.update(hir::CRATE_HIR_ID, Some(AccessLevel::Public));
 
-    {
-        let mut visitor = ObsoleteVisiblePrivateTypesVisitor {
-            tcx,
-            access_levels: &visitor.access_levels,
-            in_variant: false,
-            old_error_set: Default::default(),
-        };
-        intravisit::walk_crate(&mut visitor, krate);
+    Lrc::new(visitor.access_levels)
+}
 
+fn check_private_in_public<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, krate: CrateNum) {
+    assert_eq!(krate, LOCAL_CRATE);
 
-        let has_pub_restricted = {
-            let mut pub_restricted_visitor = PubRestrictedVisitor {
-                tcx,
-                has_pub_restricted: false
-            };
-            intravisit::walk_crate(&mut pub_restricted_visitor, krate);
-            pub_restricted_visitor.has_pub_restricted
-        };
+    let access_levels = tcx.privacy_access_levels(LOCAL_CRATE);
 
-        // Check for private types and traits in public interfaces.
-        let mut visitor = PrivateItemsInPublicInterfacesVisitor {
+    let krate = tcx.hir().krate();
+
+    let mut visitor = ObsoleteVisiblePrivateTypesVisitor {
+        tcx,
+        access_levels: &access_levels,
+        in_variant: false,
+        old_error_set: Default::default(),
+    };
+    intravisit::walk_crate(&mut visitor, krate);
+
+    let has_pub_restricted = {
+        let mut pub_restricted_visitor = PubRestrictedVisitor {
             tcx,
-            has_pub_restricted,
-            old_error_set: &visitor.old_error_set,
-            private_crates
+            has_pub_restricted: false
         };
-        krate.visit_all_item_likes(&mut DeepVisitor::new(&mut visitor));
-    }
+        intravisit::walk_crate(&mut pub_restricted_visitor, krate);
+        pub_restricted_visitor.has_pub_restricted
+    };
 
-    Lrc::new(visitor.access_levels)
+    let private_crates: FxHashSet<CrateNum> = tcx.sess.opts.extern_private.iter()
+        .flat_map(|c| {
+            tcx.crates().iter().find(|&&krate| &tcx.crate_name(krate) == c).cloned()
+        }).collect();
+
+    // Check for private types and traits in public interfaces.
+    let mut visitor = PrivateItemsInPublicInterfacesVisitor {
+        tcx,
+        has_pub_restricted,
+        old_error_set: &visitor.old_error_set,
+        private_crates
+    };
+    krate.visit_all_item_likes(&mut DeepVisitor::new(&mut visitor));
 }
 
 __build_diagnostic_array! { librustc_privacy, DIAGNOSTICS }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 2882ed47f12..28c79ce0c74 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -694,15 +694,7 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> {
 pub fn check_wf_new<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Result<(), ErrorReported> {
     tcx.sess.track_errors(|| {
         let mut visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx);
-        tcx.hir().krate().visit_all_item_likes(&mut visit);
-    })
-}
-
-pub fn check_item_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Result<(), ErrorReported> {
-    tcx.sess.track_errors(|| {
-        for &module in tcx.hir().krate().modules.keys() {
-            tcx.ensure().check_mod_item_types(tcx.hir().local_def_id(module));
-        }
+        tcx.hir().krate().par_visit_all_item_likes(&mut visit);
     })
 }
 
@@ -710,10 +702,6 @@ fn check_mod_item_types<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, module_def_id: DefId)
     tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckItemTypesVisitor { tcx });
 }
 
-pub fn check_item_bodies<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Result<(), ErrorReported> {
-    tcx.typeck_item_bodies(LOCAL_CRATE)
-}
-
 fn typeck_item_bodies<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum)
                                 -> Result<(), ErrorReported>
 {
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 81fc38e743f..fde940eb2c1 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -15,7 +15,7 @@ use syntax::feature_gate::{self, GateIssue};
 use syntax_pos::Span;
 use errors::{DiagnosticBuilder, DiagnosticId};
 
-use rustc::hir::itemlikevisit::ItemLikeVisitor;
+use rustc::hir::itemlikevisit::ParItemLikeVisitor;
 use rustc::hir;
 
 /// Helper type of a temporary returned by `.for_item(...)`.
@@ -1061,20 +1061,20 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
     }
 }
 
-impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckTypeWellFormedVisitor<'a, 'tcx> {
-    fn visit_item(&mut self, i: &'tcx hir::Item) {
+impl<'a, 'tcx> ParItemLikeVisitor<'tcx> for CheckTypeWellFormedVisitor<'a, 'tcx> {
+    fn visit_item(&self, i: &'tcx hir::Item) {
         debug!("visit_item: {:?}", i);
         let def_id = self.tcx.hir().local_def_id_from_hir_id(i.hir_id);
         self.tcx.ensure().check_item_well_formed(def_id);
     }
 
-    fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
+    fn visit_trait_item(&self, trait_item: &'tcx hir::TraitItem) {
         debug!("visit_trait_item: {:?}", trait_item);
         let def_id = self.tcx.hir().local_def_id_from_hir_id(trait_item.hir_id);
         self.tcx.ensure().check_trait_item_well_formed(def_id);
     }
 
-    fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
+    fn visit_impl_item(&self, impl_item: &'tcx hir::ImplItem) {
         debug!("visit_impl_item: {:?}", impl_item);
         let def_id = self.tcx.hir().local_def_id_from_hir_id(impl_item.hir_id);
         self.tcx.ensure().check_impl_item_well_formed(def_id);
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index 01aba658850..39a2f5d37bd 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -141,9 +141,7 @@ fn coherent_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
     for &impl_id in impls {
         check_impl_overlap(tcx, impl_id);
     }
-    use rustc::util::common::time;
-    time(tcx.sess, "builtin::check_trait checking", ||
-          builtin::check_trait(tcx, def_id));
+    builtin::check_trait(tcx, def_id);
 }
 
 pub fn check_coherence<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index fb5b06470b9..afe658767f3 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -56,12 +56,6 @@ struct OnlySelfBounds(bool);
 ///////////////////////////////////////////////////////////////////////////
 // Main entry point
 
-pub fn collect_item_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    for &module in tcx.hir().krate().modules.keys() {
-        tcx.ensure().collect_mod_item_types(tcx.hir().local_def_id(module));
-    }
-}
-
 fn collect_mod_item_types<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, module_def_id: DefId) {
     tcx.hir().visit_item_likes_in_module(
         module_def_id,
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index a918113b1fc..ebb617c23c6 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -322,8 +322,11 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
     // this ensures that later parts of type checking can assume that items
     // have valid types and not error
     tcx.sess.track_errors(|| {
-        time(tcx.sess, "type collecting", ||
-             collect::collect_item_types(tcx));
+        time(tcx.sess, "type collecting", || {
+            for &module in tcx.hir().krate().modules.keys() {
+                tcx.ensure().collect_mod_item_types(tcx.hir().local_def_id(module));
+            }
+        });
     })?;
 
     if tcx.features().rustc_attrs {
@@ -352,9 +355,15 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
 
     time(tcx.sess, "wf checking", || check::check_wf_new(tcx))?;
 
-    time(tcx.sess, "item-types checking", || check::check_item_types(tcx))?;
+    time(tcx.sess, "item-types checking", || {
+        tcx.sess.track_errors(|| {
+            for &module in tcx.hir().krate().modules.keys() {
+                tcx.ensure().check_mod_item_types(tcx.hir().local_def_id(module));
+            }
+        })
+    })?;
 
-    time(tcx.sess, "item-bodies checking", || check::check_item_bodies(tcx))?;
+    time(tcx.sess, "item-bodies checking", || tcx.typeck_item_bodies(LOCAL_CRATE))?;
 
     check_unused::check_crate(tcx);
     check_for_entry_fn(tcx);
diff --git a/src/test/ui/issues/issue-20413.rs b/src/test/ui/issues/issue-20413.rs
index 34094fe6a44..7eb6d5c0ecb 100644
--- a/src/test/ui/issues/issue-20413.rs
+++ b/src/test/ui/issues/issue-20413.rs
@@ -8,6 +8,7 @@ struct NoData<T>;
 impl<T> Foo for T where NoData<T>: Foo {
 //~^ ERROR: overflow evaluating the requirement
   fn answer(self) {
+  //~^ ERROR: overflow evaluating the requirement
     let val: NoData<T> = NoData;
   }
 }
diff --git a/src/test/ui/issues/issue-20413.stderr b/src/test/ui/issues/issue-20413.stderr
index 1c353fec8aa..db746bebbe2 100644
--- a/src/test/ui/issues/issue-20413.stderr
+++ b/src/test/ui/issues/issue-20413.stderr
@@ -12,6 +12,7 @@ error[E0275]: overflow evaluating the requirement `NoData<NoData<NoData<NoData<N
 LL | / impl<T> Foo for T where NoData<T>: Foo {
 LL | | //~^ ERROR: overflow evaluating the requirement
 LL | |   fn answer(self) {
+LL | |   //~^ ERROR: overflow evaluating the requirement
 LL | |     let val: NoData<T> = NoData;
 LL | |   }
 LL | | }
@@ -87,7 +88,86 @@ note: required by `Foo`
 LL | trait Foo {
    | ^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error[E0275]: overflow evaluating the requirement `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo`
+  --> $DIR/issue-20413.rs:10:3
+   |
+LL | /   fn answer(self) {
+LL | |   //~^ ERROR: overflow evaluating the requirement
+LL | |     let val: NoData<T> = NoData;
+LL | |   }
+   | |___^
+   |
+   = help: consider adding a `#![recursion_limit="128"]` attribute to your crate
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<NoData<T>>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<NoData<T>>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<NoData<T>>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<NoData<T>>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<NoData<T>>`
+   = note: required because of the requirements on the impl of `Foo` for `NoData<T>`
+note: required by `Foo`
+  --> $DIR/issue-20413.rs:1:1
+   |
+LL | trait Foo {
+   | ^^^^^^^^^
+
+error: aborting due to 3 previous errors
 
 Some errors occurred: E0275, E0392.
 For more information about an error, try `rustc --explain E0275`.
diff --git a/src/test/ui/issues/issue-21946.rs b/src/test/ui/issues/issue-21946.rs
index d7a6c656df9..2d99769cfa3 100644
--- a/src/test/ui/issues/issue-21946.rs
+++ b/src/test/ui/issues/issue-21946.rs
@@ -7,6 +7,7 @@ struct FooStruct;
 impl Foo for FooStruct {
 //~^ ERROR overflow evaluating the requirement `<FooStruct as Foo>::A`
     type A = <FooStruct as Foo>::A;
+    //~^ ERROR overflow evaluating the requirement `<FooStruct as Foo>::A`
 }
 
 fn main() {}
diff --git a/src/test/ui/issues/issue-21946.stderr b/src/test/ui/issues/issue-21946.stderr
index 7a178bee6ae..5ac49f61543 100644
--- a/src/test/ui/issues/issue-21946.stderr
+++ b/src/test/ui/issues/issue-21946.stderr
@@ -4,6 +4,12 @@ error[E0275]: overflow evaluating the requirement `<FooStruct as Foo>::A`
 LL | impl Foo for FooStruct {
    |      ^^^
 
-error: aborting due to previous error
+error[E0275]: overflow evaluating the requirement `<FooStruct as Foo>::A`
+  --> $DIR/issue-21946.rs:9:5
+   |
+LL |     type A = <FooStruct as Foo>::A;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0275`.
diff --git a/src/test/ui/issues/issue-23122-1.rs b/src/test/ui/issues/issue-23122-1.rs
index a882aa36af7..d6f64650f36 100644
--- a/src/test/ui/issues/issue-23122-1.rs
+++ b/src/test/ui/issues/issue-23122-1.rs
@@ -7,6 +7,7 @@ struct GetNext<T: Next> { t: T }
 impl<T: Next> Next for GetNext<T> {
     //~^ ERROR overflow evaluating the requirement
     type Next = <GetNext<T> as Next>::Next;
+    //~^ ERROR overflow evaluating the requirement
 }
 
 fn main() {}
diff --git a/src/test/ui/issues/issue-23122-1.stderr b/src/test/ui/issues/issue-23122-1.stderr
index 39dd424a86c..1b752b7afe2 100644
--- a/src/test/ui/issues/issue-23122-1.stderr
+++ b/src/test/ui/issues/issue-23122-1.stderr
@@ -4,6 +4,12 @@ error[E0275]: overflow evaluating the requirement `<GetNext<T> as Next>::Next`
 LL | impl<T: Next> Next for GetNext<T> {
    |               ^^^^
 
-error: aborting due to previous error
+error[E0275]: overflow evaluating the requirement `<GetNext<T> as Next>::Next`
+  --> $DIR/issue-23122-1.rs:9:5
+   |
+LL |     type Next = <GetNext<T> as Next>::Next;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0275`.
diff --git a/src/test/ui/issues/issue-23122-2.rs b/src/test/ui/issues/issue-23122-2.rs
index b8411200343..695712d2cc9 100644
--- a/src/test/ui/issues/issue-23122-2.rs
+++ b/src/test/ui/issues/issue-23122-2.rs
@@ -7,6 +7,7 @@ struct GetNext<T: Next> { t: T }
 impl<T: Next> Next for GetNext<T> {
     //~^ ERROR overflow evaluating the requirement
     type Next = <GetNext<T::Next> as Next>::Next;
+    //~^ ERROR overflow evaluating the requirement
 }
 
 fn main() {}
diff --git a/src/test/ui/issues/issue-23122-2.stderr b/src/test/ui/issues/issue-23122-2.stderr
index 85928775811..b122dd42373 100644
--- a/src/test/ui/issues/issue-23122-2.stderr
+++ b/src/test/ui/issues/issue-23122-2.stderr
@@ -7,6 +7,15 @@ LL | impl<T: Next> Next for GetNext<T> {
    = help: consider adding a `#![recursion_limit="128"]` attribute to your crate
    = note: required because of the requirements on the impl of `Next` for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<T as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>`
 
-error: aborting due to previous error
+error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<T as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: std::marker::Sized`
+  --> $DIR/issue-23122-2.rs:9:5
+   |
+LL |     type Next = <GetNext<T::Next> as Next>::Next;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider adding a `#![recursion_limit="128"]` attribute to your crate
+   = note: required because of the requirements on the impl of `Next` for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<T as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0275`.
diff --git a/src/test/ui/privacy/private-inferred-type.stderr b/src/test/ui/privacy/private-inferred-type.stderr
index 80a475f7dce..568d4dadc8c 100644
--- a/src/test/ui/privacy/private-inferred-type.stderr
+++ b/src/test/ui/privacy/private-inferred-type.stderr
@@ -1,3 +1,21 @@
+error[E0446]: private type `m::Priv` in public interface
+  --> $DIR/private-inferred-type.rs:61:36
+   |
+LL |     struct Priv;
+   |     - `m::Priv` declared as private
+...
+LL |     impl TraitWithAssocTy for u8 { type AssocTy = Priv; }
+   |                                    ^^^^^^^^^^^^^^^^^^^^ can't leak private type
+
+error[E0446]: private type `adjust::S2` in public interface
+  --> $DIR/private-inferred-type.rs:83:9
+   |
+LL |     struct S2;
+   |     - `adjust::S2` declared as private
+...
+LL |         type Target = S2Alias; //~ ERROR private type `adjust::S2` in public interface
+   |         ^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
+
 error: type `m::Priv` is private
   --> $DIR/private-inferred-type.rs:97:9
    |
@@ -202,24 +220,6 @@ error: type `m::Priv` is private
 LL |     match a { //~ ERROR type `m::Priv` is private
    |           ^
 
-error[E0446]: private type `m::Priv` in public interface
-  --> $DIR/private-inferred-type.rs:61:36
-   |
-LL |     struct Priv;
-   |     - `m::Priv` declared as private
-...
-LL |     impl TraitWithAssocTy for u8 { type AssocTy = Priv; }
-   |                                    ^^^^^^^^^^^^^^^^^^^^ can't leak private type
-
-error[E0446]: private type `adjust::S2` in public interface
-  --> $DIR/private-inferred-type.rs:83:9
-   |
-LL |     struct S2;
-   |     - `adjust::S2` declared as private
-...
-LL |         type Target = S2Alias; //~ ERROR private type `adjust::S2` in public interface
-   |         ^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
-
 error: aborting due to 33 previous errors
 
 For more information about this error, try `rustc --explain E0446`.