about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs2
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs127
-rw-r--r--compiler/rustc_data_structures/src/sync.rs11
-rw-r--r--compiler/rustc_hir_analysis/src/collect/lifetimes.rs7
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs4
-rw-r--r--compiler/rustc_resolve/src/imports.rs28
-rw-r--r--library/alloc/src/vec/mod.rs4
-rw-r--r--library/core/src/ffi/c_str.rs7
-rw-r--r--src/librustdoc/clean/inline.rs5
-rw-r--r--src/librustdoc/clean/mod.rs9
-rw-r--r--src/librustdoc/clean/types.rs40
-rw-r--r--src/librustdoc/clean/utils.rs9
-rw-r--r--src/librustdoc/html/format.rs151
-rw-r--r--src/librustdoc/html/render/mod.rs8
-rw-r--r--src/librustdoc/html/render/print_item.rs41
-rw-r--r--src/librustdoc/json/conversions.rs11
-rw-r--r--src/librustdoc/passes/stripper.rs8
-rw-r--r--src/test/ui/closures/binder/late-bound-in-body.rs9
-rw-r--r--src/test/ui/closures/binder/nested-closures-regions.rs9
-rw-r--r--src/test/ui/closures/binder/nested-closures-regions.stderr38
-rw-r--r--src/test/ui/closures/binder/nested-closures.rs7
-rw-r--r--src/test/ui/traits/negative-impls/eager-mono.rs12
22 files changed, 334 insertions, 213 deletions
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 8b63294fbab..0e7f243bcf3 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -2314,7 +2314,7 @@ impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx
             tcx,
             closure_substs,
             self.num_external_vids,
-            tcx.typeck_root_def_id(closure_def_id),
+            closure_def_id.expect_local(),
         );
         debug!("apply_requirements: closure_mapping={:?}", closure_mapping);
 
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index 2beb5e0ab5d..618da9e3253 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -22,7 +22,9 @@ use rustc_hir::{BodyOwnerKind, HirId};
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
 use rustc_middle::ty::fold::TypeFoldable;
-use rustc_middle::ty::{self, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt};
+use rustc_middle::ty::{
+    self, DefIdTree, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt,
+};
 use rustc_middle::ty::{InternalSubsts, SubstsRef};
 use std::iter;
 
@@ -241,7 +243,7 @@ impl<'tcx> UniversalRegions<'tcx> {
         tcx: TyCtxt<'tcx>,
         closure_substs: SubstsRef<'tcx>,
         expected_num_vars: usize,
-        typeck_root_def_id: DefId,
+        closure_def_id: LocalDefId,
     ) -> IndexVec<RegionVid, ty::Region<'tcx>> {
         let mut region_mapping = IndexVec::with_capacity(expected_num_vars);
         region_mapping.push(tcx.lifetimes.re_static);
@@ -249,7 +251,7 @@ impl<'tcx> UniversalRegions<'tcx> {
             region_mapping.push(fr);
         });
 
-        for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
+        for_each_late_bound_region_in_recursive_scope(tcx, tcx.local_parent(closure_def_id), |r| {
             region_mapping.push(r);
         });
 
@@ -339,9 +341,8 @@ impl<'tcx> UniversalRegions<'tcx> {
                 // tests, and the resulting print-outs include def-ids
                 // and other things that are not stable across tests!
                 // So we just include the region-vid. Annoying.
-                let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
-                for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
-                    err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),));
+                for_each_late_bound_region_in_recursive_scope(tcx, def_id.expect_local(), |r| {
+                    err.note(&format!("late-bound region is {:?}", self.to_region_vid(r)));
                 });
             }
             DefiningTy::Generator(def_id, substs, _) => {
@@ -354,9 +355,8 @@ impl<'tcx> UniversalRegions<'tcx> {
                 // FIXME: As above, we'd like to print out the region
                 // `r` but doing so is not stable across architectures
                 // and so forth.
-                let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
-                for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
-                    err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),));
+                for_each_late_bound_region_in_recursive_scope(tcx, def_id.expect_local(), |r| {
+                    err.note(&format!("late-bound region is {:?}", self.to_region_vid(r)));
                 });
             }
             DefiningTy::FnDef(def_id, substs) => {
@@ -421,13 +421,24 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
             first_extern_index
         } else {
             // If this is a closure, generator, or inline-const, then the late-bound regions from the enclosing
-            // function are actually external regions to us. For example, here, 'a is not local
+            // function/closures are actually external regions to us. For example, here, 'a is not local
             // to the closure c (although it is local to the fn foo):
             // fn foo<'a>() {
             //     let c = || { let x: &'a u32 = ...; }
             // }
-            self.infcx
-                .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices);
+            for_each_late_bound_region_in_recursive_scope(
+                self.infcx.tcx,
+                self.infcx.tcx.local_parent(self.mir_def.did),
+                |r| {
+                    debug!(?r);
+                    if !indices.indices.contains_key(&r) {
+                        let region_vid = self.infcx.next_nll_region_var(FR);
+                        debug!(?region_vid);
+                        indices.insert_late_bound_region(r, region_vid.to_region_vid());
+                    }
+                },
+            );
+
             // Any regions created during the execution of `defining_ty` or during the above
             // late-bound region replacement are all considered 'extern' regions
             self.infcx.num_region_vars()
@@ -444,12 +455,16 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
             bound_inputs_and_output,
             &mut indices,
         );
-        // Converse of above, if this is a function then the late-bound regions declared on its
-        // signature are local to the fn.
-        if self.mir_def.did.to_def_id() == typeck_root_def_id {
-            self.infcx
-                .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices);
-        }
+        // Converse of above, if this is a function/closure then the late-bound regions declared on its
+        // signature are local.
+        for_each_late_bound_region_in_item(self.infcx.tcx, self.mir_def.did, |r| {
+            debug!(?r);
+            if !indices.indices.contains_key(&r) {
+                let region_vid = self.infcx.next_nll_region_var(FR);
+                debug!(?region_vid);
+                indices.insert_late_bound_region(r, region_vid.to_region_vid());
+            }
+        });
 
         let (unnormalized_output_ty, mut unnormalized_input_tys) =
             inputs_and_output.split_last().unwrap();
@@ -692,7 +707,13 @@ trait InferCtxtExt<'tcx> {
     where
         T: TypeFoldable<'tcx>;
 
-    fn replace_late_bound_regions_with_nll_infer_vars(
+    fn replace_late_bound_regions_with_nll_infer_vars_in_recursive_scope(
+        &self,
+        mir_def_id: LocalDefId,
+        indices: &mut UniversalRegionIndices<'tcx>,
+    );
+
+    fn replace_late_bound_regions_with_nll_infer_vars_in_item(
         &self,
         mir_def_id: LocalDefId,
         indices: &mut UniversalRegionIndices<'tcx>,
@@ -746,13 +767,28 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
     /// set of late-bound regions and checks for any that we have not yet seen, adding them to the
     /// inputs vector.
     #[instrument(skip(self, indices))]
-    fn replace_late_bound_regions_with_nll_infer_vars(
+    fn replace_late_bound_regions_with_nll_infer_vars_in_recursive_scope(
+        &self,
+        mir_def_id: LocalDefId,
+        indices: &mut UniversalRegionIndices<'tcx>,
+    ) {
+        for_each_late_bound_region_in_recursive_scope(self.tcx, mir_def_id, |r| {
+            debug!(?r);
+            if !indices.indices.contains_key(&r) {
+                let region_vid = self.next_nll_region_var(FR);
+                debug!(?region_vid);
+                indices.insert_late_bound_region(r, region_vid.to_region_vid());
+            }
+        });
+    }
+
+    #[instrument(skip(self, indices))]
+    fn replace_late_bound_regions_with_nll_infer_vars_in_item(
         &self,
         mir_def_id: LocalDefId,
         indices: &mut UniversalRegionIndices<'tcx>,
     ) {
-        let typeck_root_def_id = self.tcx.typeck_root_def_id(mir_def_id.to_def_id());
-        for_each_late_bound_region_defined_on(self.tcx, typeck_root_def_id, |r| {
+        for_each_late_bound_region_in_item(self.tcx, mir_def_id, |r| {
             debug!(?r);
             if !indices.indices.contains_key(&r) {
                 let region_vid = self.next_nll_region_var(FR);
@@ -803,21 +839,44 @@ impl<'tcx> UniversalRegionIndices<'tcx> {
     }
 }
 
-/// Iterates over the late-bound regions defined on fn_def_id and
-/// invokes `f` with the liberated form of each one.
-fn for_each_late_bound_region_defined_on<'tcx>(
+/// Iterates over the late-bound regions defined on `mir_def_id` and all of its
+/// parents, up to the typeck root, and invokes `f` with the liberated form
+/// of each one.
+fn for_each_late_bound_region_in_recursive_scope<'tcx>(
     tcx: TyCtxt<'tcx>,
-    fn_def_id: DefId,
+    mut mir_def_id: LocalDefId,
     mut f: impl FnMut(ty::Region<'tcx>),
 ) {
-    if let Some(late_bounds) = tcx.is_late_bound_map(fn_def_id.expect_local()) {
-        for &region_def_id in late_bounds.iter() {
-            let name = tcx.item_name(region_def_id.to_def_id());
-            let liberated_region = tcx.mk_region(ty::ReFree(ty::FreeRegion {
-                scope: fn_def_id,
-                bound_region: ty::BoundRegionKind::BrNamed(region_def_id.to_def_id(), name),
-            }));
-            f(liberated_region);
+    let typeck_root_def_id = tcx.typeck_root_def_id(mir_def_id.to_def_id());
+
+    // Walk up the tree, collecting late-bound regions until we hit the typeck root
+    loop {
+        for_each_late_bound_region_in_item(tcx, mir_def_id, &mut f);
+
+        if mir_def_id.to_def_id() == typeck_root_def_id {
+            break;
+        } else {
+            mir_def_id = tcx.local_parent(mir_def_id);
         }
     }
 }
+
+/// Iterates over the late-bound regions defined on `mir_def_id` and all of its
+/// parents, up to the typeck root, and invokes `f` with the liberated form
+/// of each one.
+fn for_each_late_bound_region_in_item<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    mir_def_id: LocalDefId,
+    mut f: impl FnMut(ty::Region<'tcx>),
+) {
+    if !tcx.def_kind(mir_def_id).is_fn_like() {
+        return;
+    }
+
+    for bound_var in tcx.late_bound_vars(tcx.hir().local_def_id_to_hir_id(mir_def_id)) {
+        let ty::BoundVariableKind::Region(bound_region) = bound_var else { continue; };
+        let liberated_region = tcx
+            .mk_region(ty::ReFree(ty::FreeRegion { scope: mir_def_id.to_def_id(), bound_region }));
+        f(liberated_region);
+    }
+}
diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs
index 9c0fb8265cf..c550f246e09 100644
--- a/compiler/rustc_data_structures/src/sync.rs
+++ b/compiler/rustc_data_structures/src/sync.rs
@@ -410,6 +410,7 @@ impl<T> Lock<T> {
 
     #[cfg(parallel_compiler)]
     #[inline(always)]
+    #[track_caller]
     pub fn lock(&self) -> LockGuard<'_, T> {
         if ERROR_CHECKING {
             self.0.try_lock().expect("lock was already held")
@@ -420,21 +421,25 @@ impl<T> Lock<T> {
 
     #[cfg(not(parallel_compiler))]
     #[inline(always)]
+    #[track_caller]
     pub fn lock(&self) -> LockGuard<'_, T> {
         self.0.borrow_mut()
     }
 
     #[inline(always)]
+    #[track_caller]
     pub fn with_lock<F: FnOnce(&mut T) -> R, R>(&self, f: F) -> R {
         f(&mut *self.lock())
     }
 
     #[inline(always)]
+    #[track_caller]
     pub fn borrow(&self) -> LockGuard<'_, T> {
         self.lock()
     }
 
     #[inline(always)]
+    #[track_caller]
     pub fn borrow_mut(&self) -> LockGuard<'_, T> {
         self.lock()
     }
@@ -476,6 +481,7 @@ impl<T> RwLock<T> {
 
     #[cfg(not(parallel_compiler))]
     #[inline(always)]
+    #[track_caller]
     pub fn read(&self) -> ReadGuard<'_, T> {
         self.0.borrow()
     }
@@ -491,6 +497,7 @@ impl<T> RwLock<T> {
     }
 
     #[inline(always)]
+    #[track_caller]
     pub fn with_read_lock<F: FnOnce(&T) -> R, R>(&self, f: F) -> R {
         f(&*self.read())
     }
@@ -509,6 +516,7 @@ impl<T> RwLock<T> {
 
     #[cfg(not(parallel_compiler))]
     #[inline(always)]
+    #[track_caller]
     pub fn write(&self) -> WriteGuard<'_, T> {
         self.0.borrow_mut()
     }
@@ -524,16 +532,19 @@ impl<T> RwLock<T> {
     }
 
     #[inline(always)]
+    #[track_caller]
     pub fn with_write_lock<F: FnOnce(&mut T) -> R, R>(&self, f: F) -> R {
         f(&mut *self.write())
     }
 
     #[inline(always)]
+    #[track_caller]
     pub fn borrow(&self) -> ReadGuard<'_, T> {
         self.read()
     }
 
     #[inline(always)]
+    #[track_caller]
     pub fn borrow_mut(&self) -> WriteGuard<'_, T> {
         self.write()
     }
diff --git a/compiler/rustc_hir_analysis/src/collect/lifetimes.rs b/compiler/rustc_hir_analysis/src/collect/lifetimes.rs
index 3f263a6de24..3d07f3fbc67 100644
--- a/compiler/rustc_hir_analysis/src/collect/lifetimes.rs
+++ b/compiler/rustc_hir_analysis/src/collect/lifetimes.rs
@@ -1377,11 +1377,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             } else if let Some(body_id) = outermost_body {
                 let fn_id = self.tcx.hir().body_owner(body_id);
                 match self.tcx.hir().get(fn_id) {
-                    Node::Item(&hir::Item { kind: hir::ItemKind::Fn(..), .. })
-                    | Node::TraitItem(&hir::TraitItem {
+                    Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. })
+                    | Node::TraitItem(hir::TraitItem {
                         kind: hir::TraitItemKind::Fn(..), ..
                     })
-                    | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) => {
+                    | Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. })
+                    | Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => {
                         let scope = self.tcx.hir().local_def_id(fn_id);
                         def = Region::Free(scope.to_def_id(), def.id().unwrap());
                     }
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 3cfddd75462..58ddb807059 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -1336,6 +1336,10 @@ fn create_mono_items_for_default_impls<'tcx>(
 ) {
     match item.kind {
         hir::ItemKind::Impl(ref impl_) => {
+            if matches!(impl_.polarity, hir::ImplPolarity::Negative(_)) {
+                return;
+            }
+
             for param in impl_.generics.params {
                 match param.kind {
                     hir::GenericParamKind::Lifetime { .. } => {}
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index bdb852548b8..4c899a5ff2d 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -473,7 +473,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                 {
                     // In the case of a new import line, throw a diagnostic message
                     // for the previous line.
-                    self.throw_unresolved_import_error(errors, None);
+                    self.throw_unresolved_import_error(errors);
                     errors = vec![];
                 }
                 if seen_spans.insert(err.span) {
@@ -505,29 +505,21 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
         }
 
         if !errors.is_empty() {
-            self.throw_unresolved_import_error(errors, None);
+            self.throw_unresolved_import_error(errors);
         }
     }
 
-    fn throw_unresolved_import_error(
-        &self,
-        errors: Vec<(String, UnresolvedImportError)>,
-        span: Option<MultiSpan>,
-    ) {
+    fn throw_unresolved_import_error(&self, errors: Vec<(String, UnresolvedImportError)>) {
+        if errors.is_empty() {
+            return;
+        }
+
         /// Upper limit on the number of `span_label` messages.
         const MAX_LABEL_COUNT: usize = 10;
 
-        let (span, msg) = if errors.is_empty() {
-            (span.unwrap(), "unresolved import".to_string())
-        } else {
-            let span = MultiSpan::from_spans(errors.iter().map(|(_, err)| err.span).collect());
-
-            let paths = errors.iter().map(|(path, _)| format!("`{}`", path)).collect::<Vec<_>>();
-
-            let msg = format!("unresolved import{} {}", pluralize!(paths.len()), paths.join(", "),);
-
-            (span, msg)
-        };
+        let span = MultiSpan::from_spans(errors.iter().map(|(_, err)| err.span).collect());
+        let paths = errors.iter().map(|(path, _)| format!("`{}`", path)).collect::<Vec<_>>();
+        let msg = format!("unresolved import{} {}", pluralize!(paths.len()), paths.join(", "),);
 
         let mut diag = struct_span_err!(self.r.session, span, E0432, "{}", &msg);
 
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index bbbdc3aa2a2..834c8f58cb2 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -2588,7 +2588,7 @@ impl<T: Clone, A: Allocator> ExtendFromWithinSpec for Vec<T, A> {
         let (this, spare, len) = unsafe { self.split_at_spare_mut_with_len() };
 
         // SAFETY:
-        // - caller guaratees that src is a valid index
+        // - caller guarantees that src is a valid index
         let to_clone = unsafe { this.get_unchecked(src) };
 
         iter::zip(to_clone, spare)
@@ -2607,7 +2607,7 @@ impl<T: Copy, A: Allocator> ExtendFromWithinSpec for Vec<T, A> {
             let (init, spare) = self.split_at_spare_mut();
 
             // SAFETY:
-            // - caller guaratees that `src` is a valid index
+            // - caller guarantees that `src` is a valid index
             let source = unsafe { init.get_unchecked(src) };
 
             // SAFETY:
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index 8923f548adf..15dd9ea7e80 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -13,9 +13,9 @@ use crate::str;
 /// array of bytes. It can be constructed safely from a <code>&[[u8]]</code>
 /// slice, or unsafely from a raw `*const c_char`. It can then be
 /// converted to a Rust <code>&[str]</code> by performing UTF-8 validation, or
-/// into an owned `CString`.
+/// into an owned [`CString`].
 ///
-/// `&CStr` is to `CString` as <code>&[str]</code> is to `String`: the former
+/// `&CStr` is to [`CString`] as <code>&[str]</code> is to [`String`]: the former
 /// in each pair are borrowed references; the latter are owned
 /// strings.
 ///
@@ -24,6 +24,9 @@ use crate::str;
 /// functions may leverage the unsafe [`CStr::from_ptr`] constructor to provide
 /// a safe interface to other consumers.
 ///
+/// [`CString`]: ../../std/ffi/struct.CString.html
+/// [`String`]: ../../std/string/struct.String.html
+///
 /// # Examples
 ///
 /// Inspecting a foreign C string:
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index ec93eefb7d1..841c4f9d530 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -19,8 +19,7 @@ use rustc_span::symbol::{kw, sym, Symbol};
 use crate::clean::{
     self, clean_fn_decl_from_did_and_sig, clean_generics, clean_impl_item, clean_middle_assoc_item,
     clean_middle_field, clean_middle_ty, clean_trait_ref_with_bindings, clean_ty,
-    clean_ty_generics, clean_variant_def, clean_visibility, utils, Attributes, AttributesExt,
-    ImplKind, ItemId, Type,
+    clean_ty_generics, clean_variant_def, utils, Attributes, AttributesExt, ImplKind, ItemId, Type,
 };
 use crate::core::DocContext;
 use crate::formats::item_type::ItemType;
@@ -654,7 +653,7 @@ fn build_macro(
     match CStore::from_tcx(cx.tcx).load_macro_untracked(def_id, cx.sess()) {
         LoadedMacro::MacroDef(item_def, _) => {
             if let ast::ItemKind::MacroDef(ref def) = item_def.kind {
-                let vis = clean_visibility(cx.tcx.visibility(import_def_id.unwrap_or(def_id)));
+                let vis = cx.tcx.visibility(import_def_id.unwrap_or(def_id));
                 clean::MacroItem(clean::Macro {
                     source: utils::display_macro_source(cx, name, def, def_id, vis),
                 })
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index c5abf42c096..8d38f2df0d8 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1799,13 +1799,6 @@ pub(crate) fn clean_field_with_def_id(
     Item::from_def_id_and_parts(def_id, Some(name), StructFieldItem(ty), cx)
 }
 
-pub(crate) fn clean_visibility(vis: ty::Visibility<DefId>) -> Visibility {
-    match vis {
-        ty::Visibility::Public => Visibility::Public,
-        ty::Visibility::Restricted(module) => Visibility::Restricted(module),
-    }
-}
-
 pub(crate) fn clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocContext<'tcx>) -> Item {
     let kind = match variant.ctor_kind {
         CtorKind::Const => Variant::CLike(match variant.discr {
@@ -1962,7 +1955,7 @@ fn clean_maybe_renamed_item<'tcx>(
                 clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx)
             }
             ItemKind::Macro(ref macro_def, _) => {
-                let ty_vis = clean_visibility(cx.tcx.visibility(def_id));
+                let ty_vis = cx.tcx.visibility(def_id);
                 MacroItem(Macro {
                     source: display_macro_source(cx, name, macro_def, def_id, ty_vis),
                 })
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 3a4bfc1a740..fea3690e50a 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -24,7 +24,7 @@ use rustc_hir::{BodyId, Mutability};
 use rustc_hir_analysis::check::intrinsic::intrinsic_operation_unsafety;
 use rustc_index::vec::IndexVec;
 use rustc_middle::ty::fast_reject::SimplifiedType;
-use rustc_middle::ty::{self, DefIdTree, TyCtxt};
+use rustc_middle::ty::{self, DefIdTree, TyCtxt, Visibility};
 use rustc_session::Session;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::source_map::DUMMY_SP;
@@ -34,7 +34,6 @@ use rustc_target::abi::VariantIdx;
 use rustc_target::spec::abi::Abi;
 
 use crate::clean::cfg::Cfg;
-use crate::clean::clean_visibility;
 use crate::clean::external_path;
 use crate::clean::inline::{self, print_inlined_const};
 use crate::clean::utils::{is_literal_expr, print_const_expr, print_evaluated_const};
@@ -51,7 +50,6 @@ pub(crate) use self::Type::{
     Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, QPath,
     RawPointer, Slice, Tuple,
 };
-pub(crate) use self::Visibility::{Inherited, Public};
 
 #[cfg(test)]
 mod tests;
@@ -703,26 +701,28 @@ impl Item {
         Some(header)
     }
 
-    pub(crate) fn visibility(&self, tcx: TyCtxt<'_>) -> Visibility {
+    /// Returns the visibility of the current item. If the visibility is "inherited", then `None`
+    /// is returned.
+    pub(crate) fn visibility(&self, tcx: TyCtxt<'_>) -> Option<Visibility<DefId>> {
         let def_id = match self.item_id {
             // Anything but DefId *shouldn't* matter, but return a reasonable value anyway.
-            ItemId::Auto { .. } | ItemId::Blanket { .. } => return Visibility::Inherited,
+            ItemId::Auto { .. } | ItemId::Blanket { .. } => return None,
             // Primitives and Keywords are written in the source code as private modules.
             // The modules need to be private so that nobody actually uses them, but the
             // keywords and primitives that they are documenting are public.
-            ItemId::Primitive(..) => return Visibility::Public,
+            ItemId::Primitive(..) => return Some(Visibility::Public),
             ItemId::DefId(def_id) => def_id,
         };
 
         match *self.kind {
             // Explication on `ItemId::Primitive` just above.
-            ItemKind::KeywordItem | ItemKind::PrimitiveItem(_) => return Visibility::Public,
+            ItemKind::KeywordItem | ItemKind::PrimitiveItem(_) => return Some(Visibility::Public),
             // Variant fields inherit their enum's visibility.
             StructFieldItem(..) if is_field_vis_inherited(tcx, def_id) => {
-                return Visibility::Inherited;
+                return None;
             }
             // Variants always inherit visibility
-            VariantItem(..) => return Visibility::Inherited,
+            VariantItem(..) => return None,
             // Trait items inherit the trait's visibility
             AssocConstItem(..) | TyAssocConstItem(..) | AssocTypeItem(..) | TyAssocTypeItem(..)
             | TyMethodItem(..) | MethodItem(..) => {
@@ -736,7 +736,7 @@ impl Item {
                     }
                 };
                 if is_trait_item {
-                    return Visibility::Inherited;
+                    return None;
                 }
             }
             _ => {}
@@ -745,7 +745,7 @@ impl Item {
             Some(inlined) => inlined,
             None => def_id,
         };
-        clean_visibility(tcx.visibility(def_id))
+        Some(tcx.visibility(def_id))
     }
 }
 
@@ -2075,24 +2075,6 @@ impl From<hir::PrimTy> for PrimitiveType {
     }
 }
 
-#[derive(Copy, Clone, Debug)]
-pub(crate) enum Visibility {
-    /// `pub`
-    Public,
-    /// Visibility inherited from parent.
-    ///
-    /// For example, this is the visibility of private items and of enum variants.
-    Inherited,
-    /// `pub(crate)`, `pub(super)`, or `pub(in path::to::somewhere)`
-    Restricted(DefId),
-}
-
-impl Visibility {
-    pub(crate) fn is_public(&self) -> bool {
-        matches!(self, Visibility::Public)
-    }
-}
-
 #[derive(Clone, Debug)]
 pub(crate) struct Struct {
     pub(crate) struct_type: CtorKind,
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 518e320235f..df20dc3fc3f 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -4,9 +4,10 @@ use crate::clean::render_macro_matchers::render_macro_matcher;
 use crate::clean::{
     clean_doc_module, clean_middle_const, clean_middle_region, clean_middle_ty, inline, Crate,
     ExternalCrate, Generic, GenericArg, GenericArgs, ImportSource, Item, ItemKind, Lifetime, Path,
-    PathSegment, Primitive, PrimitiveType, Type, TypeBinding, Visibility,
+    PathSegment, Primitive, PrimitiveType, Type, TypeBinding,
 };
 use crate::core::DocContext;
+use crate::html::format::visibility_to_src_with_space;
 
 use rustc_ast as ast;
 use rustc_ast::tokenstream::TokenTree;
@@ -583,7 +584,7 @@ pub(super) fn display_macro_source(
     name: Symbol,
     def: &ast::MacroDef,
     def_id: DefId,
-    vis: Visibility,
+    vis: ty::Visibility<DefId>,
 ) -> String {
     let tts: Vec<_> = def.body.inner_tokens().into_trees().collect();
     // Extract the spans of all matchers. They represent the "interface" of the macro.
@@ -595,14 +596,14 @@ pub(super) fn display_macro_source(
         if matchers.len() <= 1 {
             format!(
                 "{}macro {}{} {{\n    ...\n}}",
-                vis.to_src_with_space(cx.tcx, def_id),
+                visibility_to_src_with_space(Some(vis), cx.tcx, def_id),
                 name,
                 matchers.map(|matcher| render_macro_matcher(cx.tcx, matcher)).collect::<String>(),
             )
         } else {
             format!(
                 "{}macro {} {{\n{}}}",
-                vis.to_src_with_space(cx.tcx, def_id),
+                visibility_to_src_with_space(Some(vis), cx.tcx, def_id),
                 name,
                 render_macro_arms(cx.tcx, matchers, ","),
             )
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 37202f786ed..06db3fb0ec4 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -1420,87 +1420,84 @@ impl clean::FnDecl {
     }
 }
 
-impl clean::Visibility {
-    pub(crate) fn print_with_space<'a, 'tcx: 'a>(
-        self,
-        item_did: ItemId,
-        cx: &'a Context<'tcx>,
-    ) -> impl fmt::Display + 'a + Captures<'tcx> {
-        use std::fmt::Write as _;
-
-        let to_print: Cow<'static, str> = match self {
-            clean::Public => "pub ".into(),
-            clean::Inherited => "".into(),
-            clean::Visibility::Restricted(vis_did) => {
-                // FIXME(camelid): This may not work correctly if `item_did` is a module.
-                //                 However, rustdoc currently never displays a module's
-                //                 visibility, so it shouldn't matter.
-                let parent_module = find_nearest_parent_module(cx.tcx(), item_did.expect_def_id());
-
-                if vis_did.is_crate_root() {
-                    "pub(crate) ".into()
-                } else if parent_module == Some(vis_did) {
-                    // `pub(in foo)` where `foo` is the parent module
-                    // is the same as no visibility modifier
-                    "".into()
-                } else if parent_module
-                    .and_then(|parent| find_nearest_parent_module(cx.tcx(), parent))
-                    == Some(vis_did)
-                {
-                    "pub(super) ".into()
-                } else {
-                    let path = cx.tcx().def_path(vis_did);
-                    debug!("path={:?}", path);
-                    // modified from `resolved_path()` to work with `DefPathData`
-                    let last_name = path.data.last().unwrap().data.get_opt_name().unwrap();
-                    let anchor = anchor(vis_did, last_name, cx).to_string();
-
-                    let mut s = "pub(in ".to_owned();
-                    for seg in &path.data[..path.data.len() - 1] {
-                        let _ = write!(s, "{}::", seg.data.get_opt_name().unwrap());
-                    }
-                    let _ = write!(s, "{}) ", anchor);
-                    s.into()
+pub(crate) fn visibility_print_with_space<'a, 'tcx: 'a>(
+    visibility: Option<ty::Visibility<DefId>>,
+    item_did: ItemId,
+    cx: &'a Context<'tcx>,
+) -> impl fmt::Display + 'a + Captures<'tcx> {
+    use std::fmt::Write as _;
+
+    let to_print: Cow<'static, str> = match visibility {
+        None => "".into(),
+        Some(ty::Visibility::Public) => "pub ".into(),
+        Some(ty::Visibility::Restricted(vis_did)) => {
+            // FIXME(camelid): This may not work correctly if `item_did` is a module.
+            //                 However, rustdoc currently never displays a module's
+            //                 visibility, so it shouldn't matter.
+            let parent_module = find_nearest_parent_module(cx.tcx(), item_did.expect_def_id());
+
+            if vis_did.is_crate_root() {
+                "pub(crate) ".into()
+            } else if parent_module == Some(vis_did) {
+                // `pub(in foo)` where `foo` is the parent module
+                // is the same as no visibility modifier
+                "".into()
+            } else if parent_module.and_then(|parent| find_nearest_parent_module(cx.tcx(), parent))
+                == Some(vis_did)
+            {
+                "pub(super) ".into()
+            } else {
+                let path = cx.tcx().def_path(vis_did);
+                debug!("path={:?}", path);
+                // modified from `resolved_path()` to work with `DefPathData`
+                let last_name = path.data.last().unwrap().data.get_opt_name().unwrap();
+                let anchor = anchor(vis_did, last_name, cx).to_string();
+
+                let mut s = "pub(in ".to_owned();
+                for seg in &path.data[..path.data.len() - 1] {
+                    let _ = write!(s, "{}::", seg.data.get_opt_name().unwrap());
                 }
+                let _ = write!(s, "{}) ", anchor);
+                s.into()
             }
-        };
-        display_fn(move |f| write!(f, "{}", to_print))
-    }
+        }
+    };
+    display_fn(move |f| write!(f, "{}", to_print))
+}
 
-    /// This function is the same as print_with_space, except that it renders no links.
-    /// It's used for macros' rendered source view, which is syntax highlighted and cannot have
-    /// any HTML in it.
-    pub(crate) fn to_src_with_space<'a, 'tcx: 'a>(
-        self,
-        tcx: TyCtxt<'tcx>,
-        item_did: DefId,
-    ) -> impl fmt::Display + 'a + Captures<'tcx> {
-        let to_print = match self {
-            clean::Public => "pub ".to_owned(),
-            clean::Inherited => String::new(),
-            clean::Visibility::Restricted(vis_did) => {
-                // FIXME(camelid): This may not work correctly if `item_did` is a module.
-                //                 However, rustdoc currently never displays a module's
-                //                 visibility, so it shouldn't matter.
-                let parent_module = find_nearest_parent_module(tcx, item_did);
-
-                if vis_did.is_crate_root() {
-                    "pub(crate) ".to_owned()
-                } else if parent_module == Some(vis_did) {
-                    // `pub(in foo)` where `foo` is the parent module
-                    // is the same as no visibility modifier
-                    String::new()
-                } else if parent_module.and_then(|parent| find_nearest_parent_module(tcx, parent))
-                    == Some(vis_did)
-                {
-                    "pub(super) ".to_owned()
-                } else {
-                    format!("pub(in {}) ", tcx.def_path_str(vis_did))
-                }
+/// This function is the same as print_with_space, except that it renders no links.
+/// It's used for macros' rendered source view, which is syntax highlighted and cannot have
+/// any HTML in it.
+pub(crate) fn visibility_to_src_with_space<'a, 'tcx: 'a>(
+    visibility: Option<ty::Visibility<DefId>>,
+    tcx: TyCtxt<'tcx>,
+    item_did: DefId,
+) -> impl fmt::Display + 'a + Captures<'tcx> {
+    let to_print = match visibility {
+        None => String::new(),
+        Some(ty::Visibility::Public) => "pub ".to_owned(),
+        Some(ty::Visibility::Restricted(vis_did)) => {
+            // FIXME(camelid): This may not work correctly if `item_did` is a module.
+            //                 However, rustdoc currently never displays a module's
+            //                 visibility, so it shouldn't matter.
+            let parent_module = find_nearest_parent_module(tcx, item_did);
+
+            if vis_did.is_crate_root() {
+                "pub(crate) ".to_owned()
+            } else if parent_module == Some(vis_did) {
+                // `pub(in foo)` where `foo` is the parent module
+                // is the same as no visibility modifier
+                String::new()
+            } else if parent_module.and_then(|parent| find_nearest_parent_module(tcx, parent))
+                == Some(vis_did)
+            {
+                "pub(super) ".to_owned()
+            } else {
+                format!("pub(in {}) ", tcx.def_path_str(vis_did))
             }
-        };
-        display_fn(move |f| f.write_str(&to_print))
-    }
+        }
+    };
+    display_fn(move |f| f.write_str(&to_print))
 }
 
 pub(crate) trait PrintWithSpace {
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index adf501a0240..3a041ae15d6 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -70,8 +70,8 @@ use crate::formats::{AssocItemRender, Impl, RenderMode};
 use crate::html::escape::Escape;
 use crate::html::format::{
     href, join_with_double_colon, print_abi_with_space, print_constness_with_space,
-    print_default_space, print_generic_bounds, print_where_clause, Buffer, Ending, HrefError,
-    PrintWithSpace,
+    print_default_space, print_generic_bounds, print_where_clause, visibility_print_with_space,
+    Buffer, Ending, HrefError, PrintWithSpace,
 };
 use crate::html::highlight;
 use crate::html::markdown::{
@@ -752,7 +752,7 @@ fn assoc_const(
         w,
         "{extra}{vis}const <a{href} class=\"constant\">{name}</a>: {ty}",
         extra = extra,
-        vis = it.visibility(tcx).print_with_space(it.item_id, cx),
+        vis = visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
         href = assoc_href_attr(it, link, cx),
         name = it.name.as_ref().unwrap(),
         ty = ty.print(cx),
@@ -809,7 +809,7 @@ fn assoc_method(
     let tcx = cx.tcx();
     let header = meth.fn_header(tcx).expect("Trying to get header from a non-function item");
     let name = meth.name.as_ref().unwrap();
-    let vis = meth.visibility(tcx).print_with_space(meth.item_id, cx).to_string();
+    let vis = visibility_print_with_space(meth.visibility(tcx), meth.item_id, cx).to_string();
     // FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove
     // this condition.
     let constness = match render_mode {
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 13df08280b5..3225ddabe2e 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -7,7 +7,7 @@ use rustc_hir::def_id::DefId;
 use rustc_middle::middle::stability;
 use rustc_middle::span_bug;
 use rustc_middle::ty::layout::LayoutError;
-use rustc_middle::ty::{Adt, TyCtxt};
+use rustc_middle::ty::{self, Adt, TyCtxt};
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_target::abi::{Layout, Primitive, TagEncoding, Variants};
@@ -28,7 +28,7 @@ use crate::formats::{AssocItemRender, Impl, RenderMode};
 use crate::html::escape::Escape;
 use crate::html::format::{
     join_with_double_colon, print_abi_with_space, print_constness_with_space, print_where_clause,
-    Buffer, Ending, PrintWithSpace,
+    visibility_print_with_space, Buffer, Ending, PrintWithSpace,
 };
 use crate::html::highlight;
 use crate::html::layout::Page;
@@ -328,14 +328,14 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
                     Some(src) => write!(
                         w,
                         "<div class=\"item-left\"><code>{}extern crate {} as {};",
-                        myitem.visibility(tcx).print_with_space(myitem.item_id, cx),
+                        visibility_print_with_space(myitem.visibility(tcx), myitem.item_id, cx),
                         anchor(myitem.item_id.expect_def_id(), src, cx),
                         myitem.name.unwrap(),
                     ),
                     None => write!(
                         w,
                         "<div class=\"item-left\"><code>{}extern crate {};",
-                        myitem.visibility(tcx).print_with_space(myitem.item_id, cx),
+                        visibility_print_with_space(myitem.visibility(tcx), myitem.item_id, cx),
                         anchor(myitem.item_id.expect_def_id(), myitem.name.unwrap(), cx),
                     ),
                 }
@@ -385,7 +385,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
                      </div>\
                      {stab_tags_before}{stab_tags}{stab_tags_after}",
                     stab = stab.unwrap_or_default(),
-                    vis = myitem.visibility(tcx).print_with_space(myitem.item_id, cx),
+                    vis = visibility_print_with_space(myitem.visibility(tcx), myitem.item_id, cx),
                     imp = import.print(cx),
                 );
                 w.write_str(ITEM_TABLE_ROW_CLOSE);
@@ -410,7 +410,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
                 let add = if stab.is_some() { " " } else { "" };
 
                 let visibility_emoji = match myitem.visibility(tcx) {
-                    clean::Visibility::Restricted(_) => {
+                    Some(ty::Visibility::Restricted(_)) => {
                         "<span title=\"Restricted Visibility\">&nbsp;🔒</span> "
                     }
                     _ => "",
@@ -503,7 +503,7 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle
     let unsafety = header.unsafety.print_with_space();
     let abi = print_abi_with_space(header.abi).to_string();
     let asyncness = header.asyncness.print_with_space();
-    let visibility = it.visibility(tcx).print_with_space(it.item_id, cx).to_string();
+    let visibility = visibility_print_with_space(it.visibility(tcx), it.item_id, cx).to_string();
     let name = it.name.unwrap();
 
     let generics_len = format!("{:#}", f.generics.print(cx)).len();
@@ -561,7 +561,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
             write!(
                 w,
                 "{}{}{}trait {}{}{}",
-                it.visibility(tcx).print_with_space(it.item_id, cx),
+                visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
                 t.unsafety(tcx).print_with_space(),
                 if t.is_auto(tcx) { "auto " } else { "" },
                 it.name.unwrap(),
@@ -1086,7 +1086,7 @@ fn item_typedef(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clea
     fn write_content(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Typedef) {
         wrap_item(w, "typedef", |w| {
             render_attributes_in_pre(w, it, "");
-            write!(w, "{}", it.visibility(cx.tcx()).print_with_space(it.item_id, cx));
+            write!(w, "{}", visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx));
             write!(
                 w,
                 "type {}{}{where_clause} = {type_};",
@@ -1183,7 +1183,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
             write!(
                 w,
                 "{}enum {}{}",
-                it.visibility(tcx).print_with_space(it.item_id, cx),
+                visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
                 it.name.unwrap(),
                 e.generics.print(cx),
             );
@@ -1398,7 +1398,7 @@ fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &cle
             write!(
                 w,
                 "{vis}const {name}: {typ}",
-                vis = it.visibility(tcx).print_with_space(it.item_id, cx),
+                vis = visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
                 name = it.name.unwrap(),
                 typ = c.type_.print(cx),
             );
@@ -1499,7 +1499,7 @@ fn item_static(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean
             write!(
                 w,
                 "{vis}static {mutability}{name}: {typ}",
-                vis = it.visibility(cx.tcx()).print_with_space(it.item_id, cx),
+                vis = visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx),
                 mutability = s.mutability.print_with_space(),
                 name = it.name.unwrap(),
                 typ = s.type_.print(cx)
@@ -1517,7 +1517,7 @@ fn item_foreign_type(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) {
             write!(
                 w,
                 "    {}type {};\n}}",
-                it.visibility(cx.tcx()).print_with_space(it.item_id, cx),
+                visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx),
                 it.name.unwrap(),
             );
         });
@@ -1671,7 +1671,12 @@ fn render_union(
     cx: &Context<'_>,
 ) {
     let tcx = cx.tcx();
-    write!(w, "{}union {}", it.visibility(tcx).print_with_space(it.item_id, cx), it.name.unwrap(),);
+    write!(
+        w,
+        "{}union {}",
+        visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
+        it.name.unwrap(),
+    );
 
     let where_displayed = g
         .map(|g| {
@@ -1698,7 +1703,7 @@ fn render_union(
             write!(
                 w,
                 "    {}{}: {},\n{}",
-                field.visibility(tcx).print_with_space(field.item_id, cx),
+                visibility_print_with_space(field.visibility(tcx), field.item_id, cx),
                 field.name.unwrap(),
                 ty.print(cx),
                 tab
@@ -1729,7 +1734,7 @@ fn render_struct(
     write!(
         w,
         "{}{}{}",
-        it.visibility(tcx).print_with_space(it.item_id, cx),
+        visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
         if structhead { "struct " } else { "" },
         it.name.unwrap()
     );
@@ -1759,7 +1764,7 @@ fn render_struct(
                         w,
                         "\n{}    {}{}: {},",
                         tab,
-                        field.visibility(tcx).print_with_space(field.item_id, cx),
+                        visibility_print_with_space(field.visibility(tcx), field.item_id, cx),
                         field.name.unwrap(),
                         ty.print(cx),
                     );
@@ -1791,7 +1796,7 @@ fn render_struct(
                         write!(
                             w,
                             "{}{}",
-                            field.visibility(tcx).print_with_space(field.item_id, cx),
+                            visibility_print_with_space(field.visibility(tcx), field.item_id, cx),
                             ty.print(cx),
                         )
                     }
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 4889ac25acb..cb8b7c18029 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -100,13 +100,12 @@ impl JsonRenderer<'_> {
         }
     }
 
-    fn convert_visibility(&self, v: clean::Visibility) -> Visibility {
-        use clean::Visibility::*;
+    fn convert_visibility(&self, v: Option<ty::Visibility<DefId>>) -> Visibility {
         match v {
-            Public => Visibility::Public,
-            Inherited => Visibility::Default,
-            Restricted(did) if did.is_crate_root() => Visibility::Crate,
-            Restricted(did) => Visibility::Restricted {
+            None => Visibility::Default,
+            Some(ty::Visibility::Public) => Visibility::Public,
+            Some(ty::Visibility::Restricted(did)) if did.is_crate_root() => Visibility::Crate,
+            Some(ty::Visibility::Restricted(did)) => Visibility::Restricted {
                 parent: from_item_id(did.into(), self.tcx),
                 path: self.tcx.def_path(did).to_string_no_crate_verbose(),
             },
diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs
index b2047360ccd..995fb5dcc1c 100644
--- a/src/librustdoc/passes/stripper.rs
+++ b/src/librustdoc/passes/stripper.rs
@@ -1,6 +1,6 @@
 //! A collection of utility functions for the `strip_*` passes.
 use rustc_hir::def_id::DefId;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{TyCtxt, Visibility};
 use rustc_span::symbol::sym;
 use std::mem;
 
@@ -81,13 +81,13 @@ impl<'a, 'tcx> DocFolder for Stripper<'a, 'tcx> {
             }
 
             clean::StructFieldItem(..) => {
-                if !i.visibility(self.tcx).is_public() {
+                if i.visibility(self.tcx) != Some(Visibility::Public) {
                     return Some(strip_item(i));
                 }
             }
 
             clean::ModuleItem(..) => {
-                if i.item_id.is_local() && !i.visibility(self.tcx).is_public() {
+                if i.item_id.is_local() && i.visibility(self.tcx) != Some(Visibility::Public) {
                     debug!("Stripper: stripping module {:?}", i.name);
                     let old = mem::replace(&mut self.update_retained, false);
                     let ret = strip_item(self.fold_item_recur(i));
@@ -246,7 +246,7 @@ impl<'tcx> DocFolder for ImportStripper<'tcx> {
     fn fold_item(&mut self, i: Item) -> Option<Item> {
         match *i.kind {
             clean::ExternCrateItem { .. } | clean::ImportItem(..)
-                if !i.visibility(self.tcx).is_public() =>
+                if i.visibility(self.tcx) != Some(Visibility::Public) =>
             {
                 None
             }
diff --git a/src/test/ui/closures/binder/late-bound-in-body.rs b/src/test/ui/closures/binder/late-bound-in-body.rs
new file mode 100644
index 00000000000..bb5c7552fda
--- /dev/null
+++ b/src/test/ui/closures/binder/late-bound-in-body.rs
@@ -0,0 +1,9 @@
+// check-pass
+
+#![feature(closure_lifetime_binder)]
+
+fn main() {
+    let _ = for<'a> || -> () {
+        let _: &'a bool = &true;
+    };
+}
diff --git a/src/test/ui/closures/binder/nested-closures-regions.rs b/src/test/ui/closures/binder/nested-closures-regions.rs
new file mode 100644
index 00000000000..6bfc6c80b78
--- /dev/null
+++ b/src/test/ui/closures/binder/nested-closures-regions.rs
@@ -0,0 +1,9 @@
+// check-pass
+
+#![feature(closure_lifetime_binder)]
+#![feature(rustc_attrs)]
+
+#[rustc_regions]
+fn main() {
+    for<'a> || -> () { for<'c> |_: &'a ()| -> () {}; };
+}
diff --git a/src/test/ui/closures/binder/nested-closures-regions.stderr b/src/test/ui/closures/binder/nested-closures-regions.stderr
new file mode 100644
index 00000000000..b385e0ed6e0
--- /dev/null
+++ b/src/test/ui/closures/binder/nested-closures-regions.stderr
@@ -0,0 +1,38 @@
+note: external requirements
+  --> $DIR/nested-closures-regions.rs:8:24
+   |
+LL |     for<'a> || -> () { for<'c> |_: &'a ()| -> () {}; };
+   |                        ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: defining type: main::{closure#0}::{closure#0} with closure substs [
+               i8,
+               extern "rust-call" fn((&(),)),
+               (),
+           ]
+   = note: late-bound region is '_#4r
+   = note: late-bound region is '_#2r
+   = note: number of external vids: 3
+   = note: where '_#1r: '_#2r
+   = note: where '_#2r: '_#1r
+
+note: no external requirements
+  --> $DIR/nested-closures-regions.rs:8:5
+   |
+LL |     for<'a> || -> () { for<'c> |_: &'a ()| -> () {}; };
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = note: defining type: main::{closure#0} with closure substs [
+               i8,
+               extern "rust-call" fn(()),
+               (),
+           ]
+   = note: late-bound region is '_#2r
+
+note: no external requirements
+  --> $DIR/nested-closures-regions.rs:7:1
+   |
+LL | fn main() {
+   | ^^^^^^^^^
+   |
+   = note: defining type: main
+
diff --git a/src/test/ui/closures/binder/nested-closures.rs b/src/test/ui/closures/binder/nested-closures.rs
new file mode 100644
index 00000000000..b3c36e7eebb
--- /dev/null
+++ b/src/test/ui/closures/binder/nested-closures.rs
@@ -0,0 +1,7 @@
+// check-pass
+
+#![feature(closure_lifetime_binder)]
+
+fn main() {
+    for<'a> || -> () { for<'c> |_: &'a ()| -> () {}; };
+}
diff --git a/src/test/ui/traits/negative-impls/eager-mono.rs b/src/test/ui/traits/negative-impls/eager-mono.rs
new file mode 100644
index 00000000000..ce770376c0b
--- /dev/null
+++ b/src/test/ui/traits/negative-impls/eager-mono.rs
@@ -0,0 +1,12 @@
+// build-pass
+// compile-flags:-C link-dead-code=y
+
+#![feature(negative_impls)]
+
+trait Foo {
+    fn foo() {}
+}
+
+impl !Foo for () {}
+
+fn main() {}