about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_error_messages/locales/en-US/privacy.ftl2
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs2
-rw-r--r--compiler/rustc_middle/src/middle/privacy.rs93
-rw-r--r--compiler/rustc_passes/src/dead.rs11
-rw-r--r--compiler/rustc_passes/src/reachable.rs10
-rw-r--r--compiler/rustc_privacy/src/errors.rs4
-rw-r--r--compiler/rustc_privacy/src/lib.rs37
-rw-r--r--compiler/rustc_resolve/src/access_levels.rs12
-rw-r--r--compiler/rustc_span/src/symbol.rs2
-rw-r--r--src/librustdoc/core.rs5
-rw-r--r--src/librustdoc/visit_ast.rs2
-rw-r--r--src/librustdoc/visit_lib.rs4
-rw-r--r--src/test/ui/privacy/access_levels.rs69
-rw-r--r--src/test/ui/privacy/access_levels.stderr151
14 files changed, 249 insertions, 155 deletions
diff --git a/compiler/rustc_error_messages/locales/en-US/privacy.ftl b/compiler/rustc_error_messages/locales/en-US/privacy.ftl
index da987152ff6..a26d1b2b381 100644
--- a/compiler/rustc_error_messages/locales/en-US/privacy.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/privacy.ftl
@@ -11,7 +11,7 @@ privacy_in_public_interface = {$vis_descr} {$kind} `{$descr}` in public interfac
     .label = can't leak {$vis_descr} {$kind}
     .visibility_label = `{$descr}` declared as {$vis_descr}
 
-privacy_report_access_level = {$descr}
+privacy_report_effective_visibility = {$descr}
 
 privacy_from_private_dep_in_public_interface =
     {$kind} `{$descr}` from private dependency '{$krate}' in public interface
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index b50c972e6f6..0f6d7ed9edc 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -762,7 +762,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     // Internal attributes, Testing:
     // ==========================================================================
 
-    rustc_attr!(TEST, rustc_access_level, Normal, template!(Word), WarnFollowing),
+    rustc_attr!(TEST, rustc_effective_visibility, Normal, template!(Word), WarnFollowing),
     rustc_attr!(TEST, rustc_outlives, Normal, template!(Word), WarnFollowing),
     rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word), WarnFollowing),
     rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word), WarnFollowing),
diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs
index 751c7f46482..c595fbec0dd 100644
--- a/compiler/rustc_middle/src/middle/privacy.rs
+++ b/compiler/rustc_middle/src/middle/privacy.rs
@@ -1,7 +1,7 @@
 //! A pass that checks to make sure private fields and methods aren't used
 //! outside their scopes. This pass will also generate a set of exported items
 //! which are available for use externally when compiled as a library.
-
+use crate::ty::Visibility;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_macros::HashStable;
@@ -27,26 +27,107 @@ pub enum AccessLevel {
     Public,
 }
 
+#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable, Default)]
+pub struct EffectiveVisibility {
+    public: Option<Visibility>,
+    exported: Option<Visibility>,
+    reachable: Option<Visibility>,
+    reachable_from_impl_trait: Option<Visibility>,
+}
+
+impl EffectiveVisibility {
+    pub fn get(&self, tag: AccessLevel) -> Option<&Visibility> {
+        match tag {
+            AccessLevel::Public => &self.public,
+            AccessLevel::Exported => &self.exported,
+            AccessLevel::Reachable => &self.reachable,
+            AccessLevel::ReachableFromImplTrait => &self.reachable_from_impl_trait,
+        }
+        .as_ref()
+    }
+
+    fn get_mut(&mut self, tag: AccessLevel) -> &mut Option<Visibility> {
+        match tag {
+            AccessLevel::Public => &mut self.public,
+            AccessLevel::Exported => &mut self.exported,
+            AccessLevel::Reachable => &mut self.reachable,
+            AccessLevel::ReachableFromImplTrait => &mut self.reachable_from_impl_trait,
+        }
+    }
+
+    pub fn is_public_at_level(&self, tag: AccessLevel) -> bool {
+        self.get(tag).map_or(false, |vis| vis.is_public())
+    }
+}
+
 /// Holds a map of accessibility levels for reachable HIR nodes.
 #[derive(Debug, Clone)]
 pub struct AccessLevels<Id = LocalDefId> {
-    pub map: FxHashMap<Id, AccessLevel>,
+    map: FxHashMap<Id, EffectiveVisibility>,
 }
 
-impl<Id: Hash + Eq> AccessLevels<Id> {
+impl<Id: Hash + Eq + Copy> AccessLevels<Id> {
+    pub fn is_public_at_level(&self, id: Id, tag: AccessLevel) -> bool {
+        self.get_effective_vis(id)
+            .map_or(false, |effective_vis| effective_vis.is_public_at_level(tag))
+    }
+
     /// See `AccessLevel::Reachable`.
     pub fn is_reachable(&self, id: Id) -> bool {
-        self.map.get(&id) >= Some(&AccessLevel::Reachable)
+        self.is_public_at_level(id, AccessLevel::Reachable)
     }
 
     /// See `AccessLevel::Exported`.
     pub fn is_exported(&self, id: Id) -> bool {
-        self.map.get(&id) >= Some(&AccessLevel::Exported)
+        self.is_public_at_level(id, AccessLevel::Exported)
     }
 
     /// See `AccessLevel::Public`.
     pub fn is_public(&self, id: Id) -> bool {
-        self.map.get(&id) >= Some(&AccessLevel::Public)
+        self.is_public_at_level(id, AccessLevel::Public)
+    }
+
+    pub fn get_access_level(&self, id: Id) -> Option<AccessLevel> {
+        self.get_effective_vis(id).and_then(|effective_vis| {
+            for level in [
+                AccessLevel::Public,
+                AccessLevel::Exported,
+                AccessLevel::Reachable,
+                AccessLevel::ReachableFromImplTrait,
+            ] {
+                if effective_vis.is_public_at_level(level) {
+                    return Some(level);
+                }
+            }
+            None
+        })
+    }
+
+    pub fn set_access_level(&mut self, id: Id, tag: AccessLevel) {
+        let mut effective_vis = self.get_effective_vis(id).copied().unwrap_or_default();
+        for level in [
+            AccessLevel::Public,
+            AccessLevel::Exported,
+            AccessLevel::Reachable,
+            AccessLevel::ReachableFromImplTrait,
+        ] {
+            if level <= tag {
+                *effective_vis.get_mut(level) = Some(Visibility::Public);
+            }
+        }
+        self.map.insert(id, effective_vis);
+    }
+
+    pub fn get_effective_vis(&self, id: Id) -> Option<&EffectiveVisibility> {
+        self.map.get(&id)
+    }
+
+    pub fn iter(&self) -> impl Iterator<Item = (&Id, &EffectiveVisibility)> {
+        self.map.iter()
+    }
+
+    pub fn map_id<OutId: Hash + Eq + Copy>(&self, f: impl Fn(Id) -> OutId) -> AccessLevels<OutId> {
+        AccessLevels { map: self.map.iter().map(|(k, v)| (f(*k), *v)).collect() }
     }
 }
 
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index f141d7beeb9..57f7c379d04 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -11,7 +11,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{Node, PatKind, TyKind};
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use rustc_middle::middle::privacy;
+use rustc_middle::middle::privacy::AccessLevel;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, DefIdTree, TyCtxt};
 use rustc_session::lint;
@@ -619,13 +619,10 @@ fn create_and_seed_worklist<'tcx>(
     // see `MarkSymbolVisitor::struct_constructors`
     let mut struct_constructors = Default::default();
     let mut worklist = access_levels
-        .map
         .iter()
-        .filter_map(
-            |(&id, &level)| {
-                if level >= privacy::AccessLevel::Reachable { Some(id) } else { None }
-            },
-        )
+        .filter_map(|(&id, effective_vis)| {
+            effective_vis.is_public_at_level(AccessLevel::Reachable).then_some(id)
+        })
         // Seed entry point
         .chain(tcx.entry_fn(()).and_then(|(def_id, _)| def_id.as_local()))
         .collect::<Vec<_>>();
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index f7e3fac6b2e..75244124e20 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -12,7 +12,7 @@ use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::Node;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
-use rustc_middle::middle::privacy;
+use rustc_middle::middle::privacy::{self, AccessLevel};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, DefIdTree, TyCtxt};
 use rustc_session::config::CrateType;
@@ -373,7 +373,13 @@ fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashSet<LocalDefId> {
     //         If other crates link to us, they're going to expect to be able to
     //         use the lang items, so we need to be sure to mark them as
     //         exported.
-    reachable_context.worklist.extend(access_levels.map.keys());
+    reachable_context.worklist = access_levels
+        .iter()
+        .filter_map(|(&id, effective_vis)| {
+            effective_vis.is_public_at_level(AccessLevel::ReachableFromImplTrait).then_some(id)
+        })
+        .collect::<Vec<_>>();
+
     for item in tcx.lang_items().items().iter() {
         if let Some(def_id) = *item {
             if let Some(def_id) = def_id.as_local() {
diff --git a/compiler/rustc_privacy/src/errors.rs b/compiler/rustc_privacy/src/errors.rs
index 63f83f8965e..705ad567aa7 100644
--- a/compiler/rustc_privacy/src/errors.rs
+++ b/compiler/rustc_privacy/src/errors.rs
@@ -76,8 +76,8 @@ pub struct InPublicInterface<'a> {
 }
 
 #[derive(SessionDiagnostic)]
-#[diag(privacy::report_access_level)]
-pub struct ReportAccessLevel {
+#[diag(privacy::report_effective_visibility)]
+pub struct ReportEffectiveVisibility {
     #[primary_span]
     pub span: Span,
     pub descr: String,
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 48ab31ab92d..8f5ee51e6cf 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -42,7 +42,7 @@ use std::{cmp, fmt, mem};
 
 use errors::{
     FieldIsPrivate, FieldIsPrivateLabel, FromPrivateDependencyInPublicInterface, InPublicInterface,
-    InPublicInterfaceTraits, ItemIsPrivate, PrivateInPublicLint, ReportAccessLevel,
+    InPublicInterfaceTraits, ItemIsPrivate, PrivateInPublicLint, ReportEffectiveVisibility,
     UnnamedItemIsPrivate,
 };
 
@@ -376,7 +376,7 @@ impl VisibilityLike for Option<AccessLevel> {
     // (which require reaching the `DefId`s in them).
     const SHALLOW: bool = true;
     fn new_min(find: &FindMin<'_, '_, Self>, def_id: LocalDefId) -> Self {
-        cmp::min(find.access_levels.map.get(&def_id).copied(), find.min)
+        cmp::min(find.access_levels.get_access_level(def_id), find.min)
     }
 }
 
@@ -416,7 +416,7 @@ struct ReachEverythingInTheInterfaceVisitor<'a, 'tcx> {
 
 impl<'tcx> EmbargoVisitor<'tcx> {
     fn get(&self, def_id: LocalDefId) -> Option<AccessLevel> {
-        self.access_levels.map.get(&def_id).copied()
+        self.access_levels.get_access_level(def_id)
     }
 
     fn update_with_hir_id(
@@ -433,7 +433,7 @@ impl<'tcx> EmbargoVisitor<'tcx> {
         let old_level = self.get(def_id);
         // Accessibility levels can only grow.
         if level > old_level {
-            self.access_levels.map.insert(def_id, level.unwrap());
+            self.access_levels.set_access_level(def_id, level.unwrap());
             self.changed = true;
             level
         } else {
@@ -914,10 +914,31 @@ pub struct TestReachabilityVisitor<'tcx, 'a> {
 
 impl<'tcx, 'a> TestReachabilityVisitor<'tcx, 'a> {
     fn access_level_diagnostic(&mut self, def_id: LocalDefId) {
-        if self.tcx.has_attr(def_id.to_def_id(), sym::rustc_access_level) {
-            let access_level = format!("{:?}", self.access_levels.map.get(&def_id));
-            let span = self.tcx.def_span(def_id.to_def_id());
-            self.tcx.sess.emit_err(ReportAccessLevel { span, descr: access_level });
+        let span = self.tcx.def_span(def_id.to_def_id());
+        if self.tcx.has_attr(def_id.to_def_id(), sym::rustc_effective_visibility) {
+            let mut error_msg = String::new();
+
+            let effective_vis =
+                self.access_levels.get_effective_vis(def_id).copied().unwrap_or_default();
+            for level in [
+                AccessLevel::Public,
+                AccessLevel::Exported,
+                AccessLevel::Reachable,
+                AccessLevel::ReachableFromImplTrait,
+            ] {
+                let vis_str = match effective_vis.get(level) {
+                    Some(ty::Visibility::Restricted(restricted_id)) => {
+                        format!("pub({})", self.tcx.item_name(restricted_id.to_def_id()))
+                    }
+                    Some(ty::Visibility::Public) => "pub".to_string(),
+                    None => "pub(self)".to_string(),
+                };
+                if level != AccessLevel::Public {
+                    error_msg.push_str(", ");
+                }
+                error_msg.push_str(&format!("{:?}: {}", level, vis_str));
+            }
+            self.tcx.sess.emit_err(ReportEffectiveVisibility { span, descr: error_msg });
         }
     }
 }
diff --git a/compiler/rustc_resolve/src/access_levels.rs b/compiler/rustc_resolve/src/access_levels.rs
index 0a3add2e0f5..9b1111c02c7 100644
--- a/compiler/rustc_resolve/src/access_levels.rs
+++ b/compiler/rustc_resolve/src/access_levels.rs
@@ -46,7 +46,7 @@ impl<'r, 'a> AccessLevelsVisitor<'r, 'a> {
     /// This will also follow `use` chains (see PrivacyVisitor::set_import_binding_access_level).
     fn set_bindings_access_level(&mut self, module_id: LocalDefId) {
         assert!(self.r.module_map.contains_key(&&module_id.to_def_id()));
-        let module_level = self.r.access_levels.map.get(&module_id).copied();
+        let module_level = self.r.access_levels.get_access_level(module_id);
         if !module_level.is_some() {
             return;
         }
@@ -103,9 +103,9 @@ impl<'r, 'a> AccessLevelsVisitor<'r, 'a> {
         def_id: LocalDefId,
         access_level: Option<AccessLevel>,
     ) -> Option<AccessLevel> {
-        let old_level = self.r.access_levels.map.get(&def_id).copied();
+        let old_level = self.r.access_levels.get_access_level(def_id);
         if old_level < access_level {
-            self.r.access_levels.map.insert(def_id, access_level.unwrap());
+            self.r.access_levels.set_access_level(def_id, access_level.unwrap());
             self.changed = true;
             access_level
         } else {
@@ -131,7 +131,7 @@ impl<'r, 'ast> Visitor<'ast> for AccessLevelsVisitor<'ast, 'r> {
             // Foreign modules inherit level from parents.
             ast::ItemKind::ForeignMod(..) => {
                 let parent_level =
-                    self.r.access_levels.map.get(&self.r.local_parent(def_id)).copied();
+                    self.r.access_levels.get_access_level(self.r.local_parent(def_id));
                 self.set_access_level(item.id, parent_level);
             }
 
@@ -151,7 +151,7 @@ impl<'r, 'ast> Visitor<'ast> for AccessLevelsVisitor<'ast, 'r> {
                 self.set_bindings_access_level(def_id);
                 for variant in variants {
                     let variant_def_id = self.r.local_def_id(variant.id);
-                    let variant_level = self.r.access_levels.map.get(&variant_def_id).copied();
+                    let variant_level = self.r.access_levels.get_access_level(variant_def_id);
                     for field in variant.data.fields() {
                         self.set_access_level(field.id, variant_level);
                     }
@@ -159,7 +159,7 @@ impl<'r, 'ast> Visitor<'ast> for AccessLevelsVisitor<'ast, 'r> {
             }
 
             ast::ItemKind::Struct(ref def, _) | ast::ItemKind::Union(ref def, _) => {
-                let inherited_level = self.r.access_levels.map.get(&def_id).copied();
+                let inherited_level = self.r.access_levels.get_access_level(def_id);
                 for field in def.fields() {
                     if field.vis.kind.is_pub() {
                         self.set_access_level(field.id, inherited_level);
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index ae4d1a4635b..562360130e9 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1214,7 +1214,6 @@ symbols! {
         rust_eh_unregister_frames,
         rust_oom,
         rustc,
-        rustc_access_level,
         rustc_allocator,
         rustc_allocator_nounwind,
         rustc_allocator_zeroed,
@@ -1242,6 +1241,7 @@ symbols! {
         rustc_dump_program_clauses,
         rustc_dump_user_substs,
         rustc_dump_vtable,
+        rustc_effective_visibility,
         rustc_error,
         rustc_evaluate_where_clauses,
         rustc_expected_cgu_reuse,
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index c48b25aea4a..76562d26a55 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -10,7 +10,6 @@ use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{HirId, Path, TraitCandidate};
 use rustc_interface::interface;
 use rustc_middle::hir::nested_filter;
-use rustc_middle::middle::privacy::AccessLevels;
 use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
 use rustc_resolve as resolve;
 use rustc_session::config::{self, CrateType, ErrorOutputType};
@@ -364,9 +363,7 @@ pub(crate) fn run_global_ctxt(
         .copied()
         .filter(|&trait_def_id| tcx.trait_is_auto(trait_def_id))
         .collect();
-    let access_levels = AccessLevels {
-        map: tcx.privacy_access_levels(()).map.iter().map(|(k, v)| (k.to_def_id(), *v)).collect(),
-    };
+    let access_levels = tcx.privacy_access_levels(()).map_id(Into::into);
 
     let mut ctxt = DocContext {
         tcx,
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index c27ac0ac40e..e6cef4a326a 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -230,7 +230,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                     } else {
                         // All items need to be handled here in case someone wishes to link
                         // to them with intra-doc links
-                        self.cx.cache.access_levels.map.insert(did, AccessLevel::Public);
+                        self.cx.cache.access_levels.set_access_level(did, AccessLevel::Public);
                     }
                 }
             }
diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs
index f01ec38665c..8221e0998d7 100644
--- a/src/librustdoc/visit_lib.rs
+++ b/src/librustdoc/visit_lib.rs
@@ -38,10 +38,10 @@ impl<'a, 'tcx> LibEmbargoVisitor<'a, 'tcx> {
     fn update(&mut self, did: DefId, level: Option<AccessLevel>) -> Option<AccessLevel> {
         let is_hidden = self.tcx.is_doc_hidden(did);
 
-        let old_level = self.access_levels.map.get(&did).cloned();
+        let old_level = self.access_levels.get_access_level(did);
         // Accessibility levels can only grow
         if level > old_level && !is_hidden {
-            self.access_levels.map.insert(did, level.unwrap());
+            self.access_levels.set_access_level(did, level.unwrap());
             level
         } else {
             old_level
diff --git a/src/test/ui/privacy/access_levels.rs b/src/test/ui/privacy/access_levels.rs
index d51d2b57267..aa718ab9254 100644
--- a/src/test/ui/privacy/access_levels.rs
+++ b/src/test/ui/privacy/access_levels.rs
@@ -1,49 +1,62 @@
 #![feature(rustc_attrs)]
 
-#[rustc_access_level] mod outer { //~ ERROR None
-    #[rustc_access_level] pub mod inner { //~ ERROR Some(Exported)
-        #[rustc_access_level]
-        extern "C" { //~ ERROR Some(Exported)
-            #[rustc_access_level] static a: u8; //~ ERROR None
-            #[rustc_access_level] pub fn b(); //~ ERROR Some(Exported)
-        }
-        #[rustc_access_level]
-        pub trait Trait { //~ ERROR Some(Exported)
-            #[rustc_access_level] const A: i32; //~ ERROR Some(Exported)
-            #[rustc_access_level] type B; //~ ERROR Some(Exported)
+#[rustc_effective_visibility]
+mod outer { //~ ERROR Public: pub(self), Exported: pub(self), Reachable: pub(self), ReachableFromImplTrait: pub(self)
+    #[rustc_effective_visibility]
+    pub mod inner1 { //~ ERROR Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+
+        #[rustc_effective_visibility]
+        extern "C" {} //~ ERROR Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+
+        #[rustc_effective_visibility]
+        pub trait PubTrait { //~ ERROR Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+            #[rustc_effective_visibility]
+            const A: i32; //~ ERROR Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+            #[rustc_effective_visibility]
+            type B; //~ ERROR Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
         }
 
-        #[rustc_access_level]
-        pub struct Struct { //~ ERROR Some(Exported)
-            #[rustc_access_level] a: u8, //~ ERROR None
-            #[rustc_access_level] pub b: u8, //~ ERROR Some(Exported)
-        }
+        #[rustc_effective_visibility]
+        struct PrivStruct; //~ ERROR Public: pub(self), Exported: pub(self), Reachable: pub(self), ReachableFromImplTrait: pub(self)
 
-        #[rustc_access_level]
-        pub union Union { //~ ERROR Some(Exported)
-            #[rustc_access_level] a: u8, //~ ERROR None
-            #[rustc_access_level] pub b: u8, //~ ERROR Some(Exported)
+        #[rustc_effective_visibility]
+        pub union PubUnion { //~ ERROR Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+            #[rustc_effective_visibility]
+            a: u8, //~ ERROR Public: pub(self), Exported: pub(self), Reachable: pub(self), ReachableFromImplTrait: pub(self)
+            #[rustc_effective_visibility]
+            pub b: u8, //~ ERROR Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
         }
 
-        #[rustc_access_level]
-        pub enum Enum { //~ ERROR Some(Exported)
-            #[rustc_access_level] A( //~ ERROR Some(Exported)
-                #[rustc_access_level] Struct, //~ ERROR Some(Exported)
-                #[rustc_access_level] Union,  //~ ERROR Some(Exported)
+        #[rustc_effective_visibility]
+        pub enum Enum { //~ ERROR Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+            #[rustc_effective_visibility]
+            A( //~ ERROR Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+                #[rustc_effective_visibility]
+                PubUnion,  //~ ERROR Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
             ),
         }
     }
 
-    #[rustc_access_level] macro_rules! none_macro { //~ ERROR None
+    #[rustc_effective_visibility]
+    macro_rules! none_macro { //~ Public: pub(self), Exported: pub(self), Reachable: pub(self), ReachableFromImplTrait: pub(self)
         () => {};
     }
 
     #[macro_export]
-    #[rustc_access_level] macro_rules! public_macro { //~ ERROR Some(Public)
+    #[rustc_effective_visibility]
+    macro_rules! public_macro { //~ Public: pub, Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
         () => {};
     }
+
+    #[rustc_effective_visibility]
+    pub struct ReachableStruct { //~ ERROR Public: pub(self), Exported: pub(self), Reachable: pub, ReachableFromImplTrait: pub
+        #[rustc_effective_visibility]
+        pub a: u8, //~ ERROR Public: pub(self), Exported: pub(self), Reachable: pub, ReachableFromImplTrait: pub
+    }
 }
 
-pub use outer::inner;
+pub use outer::inner1;
+
+pub fn foo() -> outer::ReachableStruct { outer::ReachableStruct {a: 0} }
 
 fn main() {}
diff --git a/src/test/ui/privacy/access_levels.stderr b/src/test/ui/privacy/access_levels.stderr
index f326293c384..2ed6c330a2f 100644
--- a/src/test/ui/privacy/access_levels.stderr
+++ b/src/test/ui/privacy/access_levels.stderr
@@ -1,125 +1,104 @@
-error: None
-  --> $DIR/access_levels.rs:3:23
+error: Public: pub(self), Exported: pub(self), Reachable: pub(self), ReachableFromImplTrait: pub(self)
+  --> $DIR/access_levels.rs:4:1
    |
-LL | #[rustc_access_level] mod outer {
-   |                       ^^^^^^^^^
+LL | mod outer {
+   | ^^^^^^^^^
 
-error: Some(Exported)
-  --> $DIR/access_levels.rs:4:27
+error: Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+  --> $DIR/access_levels.rs:6:5
    |
-LL |     #[rustc_access_level] pub mod inner {
-   |                           ^^^^^^^^^^^^^
+LL |     pub mod inner1 {
+   |     ^^^^^^^^^^^^^^
 
-error: Some(Exported)
-  --> $DIR/access_levels.rs:6:9
+error: Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+  --> $DIR/access_levels.rs:9:9
    |
-LL | /         extern "C" {
-LL | |             #[rustc_access_level] static a: u8;
-LL | |             #[rustc_access_level] pub fn b();
-LL | |         }
-   | |_________^
+LL |         extern "C" {}
+   |         ^^^^^^^^^^^^^
 
-error: Some(Exported)
-  --> $DIR/access_levels.rs:11:9
+error: Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+  --> $DIR/access_levels.rs:12:9
    |
-LL |         pub trait Trait {
-   |         ^^^^^^^^^^^^^^^
+LL |         pub trait PubTrait {
+   |         ^^^^^^^^^^^^^^^^^^
 
-error: Some(Exported)
-  --> $DIR/access_levels.rs:17:9
+error: Public: pub(self), Exported: pub(self), Reachable: pub(self), ReachableFromImplTrait: pub(self)
+  --> $DIR/access_levels.rs:20:9
    |
-LL |         pub struct Struct {
+LL |         struct PrivStruct;
    |         ^^^^^^^^^^^^^^^^^
 
-error: None
-  --> $DIR/access_levels.rs:18:35
-   |
-LL |             #[rustc_access_level] a: u8,
-   |                                   ^^^^^
-
-error: Some(Exported)
-  --> $DIR/access_levels.rs:19:35
-   |
-LL |             #[rustc_access_level] pub b: u8,
-   |                                   ^^^^^^^^^
-
-error: Some(Exported)
+error: Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
   --> $DIR/access_levels.rs:23:9
    |
-LL |         pub union Union {
-   |         ^^^^^^^^^^^^^^^
+LL |         pub union PubUnion {
+   |         ^^^^^^^^^^^^^^^^^^
 
-error: None
-  --> $DIR/access_levels.rs:24:35
+error: Public: pub(self), Exported: pub(self), Reachable: pub(self), ReachableFromImplTrait: pub(self)
+  --> $DIR/access_levels.rs:25:13
    |
-LL |             #[rustc_access_level] a: u8,
-   |                                   ^^^^^
+LL |             a: u8,
+   |             ^^^^^
 
-error: Some(Exported)
-  --> $DIR/access_levels.rs:25:35
+error: Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+  --> $DIR/access_levels.rs:27:13
    |
-LL |             #[rustc_access_level] pub b: u8,
-   |                                   ^^^^^^^^^
+LL |             pub b: u8,
+   |             ^^^^^^^^^
 
-error: Some(Exported)
-  --> $DIR/access_levels.rs:29:9
+error: Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+  --> $DIR/access_levels.rs:31:9
    |
 LL |         pub enum Enum {
    |         ^^^^^^^^^^^^^
 
-error: Some(Exported)
-  --> $DIR/access_levels.rs:30:35
-   |
-LL |             #[rustc_access_level] A(
-   |                                   ^
-
-error: Some(Exported)
-  --> $DIR/access_levels.rs:31:39
+error: Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+  --> $DIR/access_levels.rs:33:13
    |
-LL |                 #[rustc_access_level] Struct,
-   |                                       ^^^^^^
+LL |             A(
+   |             ^
 
-error: Some(Exported)
-  --> $DIR/access_levels.rs:32:39
+error: Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+  --> $DIR/access_levels.rs:35:17
    |
-LL |                 #[rustc_access_level] Union,
-   |                                       ^^^^^
+LL |                 PubUnion,
+   |                 ^^^^^^^^
 
-error: None
-  --> $DIR/access_levels.rs:37:27
+error: Public: pub(self), Exported: pub(self), Reachable: pub(self), ReachableFromImplTrait: pub(self)
+  --> $DIR/access_levels.rs:41:5
    |
-LL |     #[rustc_access_level] macro_rules! none_macro {
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^
+LL |     macro_rules! none_macro {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
 
-error: Some(Public)
-  --> $DIR/access_levels.rs:42:27
+error: Public: pub, Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+  --> $DIR/access_levels.rs:47:5
    |
-LL |     #[rustc_access_level] macro_rules! public_macro {
-   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     macro_rules! public_macro {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: Some(Exported)
-  --> $DIR/access_levels.rs:12:35
+error: Public: pub(self), Exported: pub(self), Reachable: pub, ReachableFromImplTrait: pub
+  --> $DIR/access_levels.rs:52:5
    |
-LL |             #[rustc_access_level] const A: i32;
-   |                                   ^^^^^^^^^^^^
+LL |     pub struct ReachableStruct {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: Some(Exported)
-  --> $DIR/access_levels.rs:13:35
+error: Public: pub(self), Exported: pub(self), Reachable: pub, ReachableFromImplTrait: pub
+  --> $DIR/access_levels.rs:54:9
    |
-LL |             #[rustc_access_level] type B;
-   |                                   ^^^^^^
+LL |         pub a: u8,
+   |         ^^^^^^^^^
 
-error: None
-  --> $DIR/access_levels.rs:7:35
+error: Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+  --> $DIR/access_levels.rs:14:13
    |
-LL |             #[rustc_access_level] static a: u8;
-   |                                   ^^^^^^^^^^^^
+LL |             const A: i32;
+   |             ^^^^^^^^^^^^
 
-error: Some(Exported)
-  --> $DIR/access_levels.rs:8:35
+error: Public: pub(self), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
+  --> $DIR/access_levels.rs:16:13
    |
-LL |             #[rustc_access_level] pub fn b();
-   |                                   ^^^^^^^^^^
+LL |             type B;
+   |             ^^^^^^
 
-error: aborting due to 20 previous errors
+error: aborting due to 17 previous errors