Skip to content

Commit 496ccd9

Browse files
committed
Populate effective visibilities in 'rustc_resolve'
1 parent e20fabb commit 496ccd9

File tree

7 files changed

+240
-163
lines changed

7 files changed

+240
-163
lines changed

compiler/rustc_middle/src/middle/privacy.rs

+104-32
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
//! A pass that checks to make sure private fields and methods aren't used
22
//! outside their scopes. This pass will also generate a set of exported items
33
//! which are available for use externally when compiled as a library.
4-
use crate::ty::Visibility;
4+
use crate::ty::{DefIdTree, Visibility};
55
use rustc_data_structures::fx::FxHashMap;
66
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
77
use rustc_macros::HashStable;
88
use rustc_query_system::ich::StableHashingContext;
9-
use rustc_span::def_id::LocalDefId;
9+
use rustc_span::def_id::{DefId, LocalDefId};
1010
use std::hash::Hash;
1111

1212
/// Represents the levels of accessibility an item can have.
@@ -27,26 +27,36 @@ pub enum AccessLevel {
2727
Public,
2828
}
2929

30-
#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable, Default)]
30+
impl AccessLevel {
31+
pub fn all_levels() -> [AccessLevel; 4] {
32+
[
33+
AccessLevel::Public,
34+
AccessLevel::Exported,
35+
AccessLevel::Reachable,
36+
AccessLevel::ReachableFromImplTrait,
37+
]
38+
}
39+
}
40+
41+
#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable)]
3142
pub struct EffectiveVisibility {
32-
public: Option<Visibility>,
33-
exported: Option<Visibility>,
34-
reachable: Option<Visibility>,
35-
reachable_from_impl_trait: Option<Visibility>,
43+
public: Visibility,
44+
exported: Visibility,
45+
reachable: Visibility,
46+
reachable_from_impl_trait: Visibility,
3647
}
3748

3849
impl EffectiveVisibility {
39-
pub fn get(&self, tag: AccessLevel) -> Option<&Visibility> {
50+
pub fn get(&self, tag: AccessLevel) -> &Visibility {
4051
match tag {
4152
AccessLevel::Public => &self.public,
4253
AccessLevel::Exported => &self.exported,
4354
AccessLevel::Reachable => &self.reachable,
4455
AccessLevel::ReachableFromImplTrait => &self.reachable_from_impl_trait,
4556
}
46-
.as_ref()
4757
}
4858

49-
fn get_mut(&mut self, tag: AccessLevel) -> &mut Option<Visibility> {
59+
fn get_mut(&mut self, tag: AccessLevel) -> &mut Visibility {
5060
match tag {
5161
AccessLevel::Public => &mut self.public,
5262
AccessLevel::Exported => &mut self.exported,
@@ -56,7 +66,30 @@ impl EffectiveVisibility {
5666
}
5767

5868
pub fn is_public_at_level(&self, tag: AccessLevel) -> bool {
59-
self.get(tag).map_or(false, |vis| vis.is_public())
69+
self.get(tag).is_public()
70+
}
71+
72+
fn update(&mut self, vis: Visibility, tag: AccessLevel, tree: impl DefIdTree) -> bool {
73+
let mut changed = false;
74+
for level in AccessLevel::all_levels() {
75+
if level <= tag {
76+
let current_effective_vis = self.get_mut(level);
77+
if *current_effective_vis != vis && vis.is_at_least(*current_effective_vis, tree) {
78+
changed = true;
79+
*current_effective_vis = vis;
80+
}
81+
}
82+
}
83+
changed
84+
}
85+
86+
fn from_vis(vis: Visibility) -> EffectiveVisibility {
87+
EffectiveVisibility {
88+
public: vis,
89+
exported: vis,
90+
reachable: vis,
91+
reachable_from_impl_trait: vis,
92+
}
6093
}
6194
}
6295

@@ -89,12 +122,7 @@ impl<Id: Hash + Eq + Copy> AccessLevels<Id> {
89122

90123
pub fn get_access_level(&self, id: Id) -> Option<AccessLevel> {
91124
self.get_effective_vis(id).and_then(|effective_vis| {
92-
for level in [
93-
AccessLevel::Public,
94-
AccessLevel::Exported,
95-
AccessLevel::Reachable,
96-
AccessLevel::ReachableFromImplTrait,
97-
] {
125+
for level in AccessLevel::all_levels() {
98126
if effective_vis.is_public_at_level(level) {
99127
return Some(level);
100128
}
@@ -103,21 +131,6 @@ impl<Id: Hash + Eq + Copy> AccessLevels<Id> {
103131
})
104132
}
105133

106-
pub fn set_access_level(&mut self, id: Id, tag: AccessLevel) {
107-
let mut effective_vis = self.get_effective_vis(id).copied().unwrap_or_default();
108-
for level in [
109-
AccessLevel::Public,
110-
AccessLevel::Exported,
111-
AccessLevel::Reachable,
112-
AccessLevel::ReachableFromImplTrait,
113-
] {
114-
if level <= tag {
115-
*effective_vis.get_mut(level) = Some(Visibility::Public);
116-
}
117-
}
118-
self.map.insert(id, effective_vis);
119-
}
120-
121134
pub fn get_effective_vis(&self, id: Id) -> Option<&EffectiveVisibility> {
122135
self.map.get(&id)
123136
}
@@ -129,6 +142,65 @@ impl<Id: Hash + Eq + Copy> AccessLevels<Id> {
129142
pub fn map_id<OutId: Hash + Eq + Copy>(&self, f: impl Fn(Id) -> OutId) -> AccessLevels<OutId> {
130143
AccessLevels { map: self.map.iter().map(|(k, v)| (f(*k), *v)).collect() }
131144
}
145+
146+
pub fn set_access_level(
147+
&mut self,
148+
id: Id,
149+
default_vis: impl FnOnce() -> Visibility,
150+
tag: AccessLevel,
151+
) {
152+
let mut effective_vis = self
153+
.get_effective_vis(id)
154+
.copied()
155+
.unwrap_or_else(|| EffectiveVisibility::from_vis(default_vis()));
156+
for level in AccessLevel::all_levels() {
157+
if level <= tag {
158+
*effective_vis.get_mut(level) = Visibility::Public;
159+
}
160+
}
161+
self.map.insert(id, effective_vis);
162+
}
163+
}
164+
165+
impl<Id: Hash + Eq + Copy + Into<DefId>> AccessLevels<Id> {
166+
// `parent_id` is not necessarily a parent in source code tree,
167+
// it is the node from which the maximum effective visibility is inherited.
168+
pub fn update(
169+
&mut self,
170+
id: Id,
171+
nominal_vis: Visibility,
172+
default_vis: impl FnOnce() -> Visibility,
173+
parent_id: Id,
174+
tag: AccessLevel,
175+
tree: impl DefIdTree,
176+
) -> Result<bool, ()> {
177+
let mut changed = false;
178+
let mut current_effective_vis = self
179+
.get_effective_vis(id)
180+
.copied()
181+
.unwrap_or_else(|| EffectiveVisibility::from_vis(default_vis()));
182+
if let Some(inherited_effective_vis) = self.get_effective_vis(parent_id) {
183+
for level in AccessLevel::all_levels() {
184+
if tag >= level {
185+
let inherited_effective_vis_at_level = *inherited_effective_vis.get(level);
186+
let calculated_effective_vis =
187+
if nominal_vis.is_at_least(inherited_effective_vis_at_level, tree) {
188+
inherited_effective_vis_at_level
189+
} else {
190+
nominal_vis
191+
};
192+
changed |= current_effective_vis.update(calculated_effective_vis, level, tree);
193+
}
194+
}
195+
} else {
196+
if !id.into().is_crate_root() {
197+
return Err(());
198+
}
199+
changed |= current_effective_vis.update(Visibility::Public, AccessLevel::Public, tree);
200+
}
201+
self.map.insert(id, current_effective_vis);
202+
Ok(changed)
203+
}
132204
}
133205

134206
impl<Id> Default for AccessLevels<Id> {

compiler/rustc_privacy/src/lib.rs

+25-22
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,11 @@ impl<'tcx> EmbargoVisitor<'tcx> {
433433
let old_level = self.get(def_id);
434434
// Accessibility levels can only grow.
435435
if level > old_level {
436-
self.access_levels.set_access_level(def_id, level.unwrap());
436+
self.access_levels.set_access_level(
437+
def_id,
438+
|| ty::Visibility::Restricted(self.tcx.parent_module_from_def_id(def_id)),
439+
level.unwrap(),
440+
);
437441
self.changed = true;
438442
level
439443
} else {
@@ -921,31 +925,30 @@ pub struct TestReachabilityVisitor<'tcx, 'a> {
921925

922926
impl<'tcx, 'a> TestReachabilityVisitor<'tcx, 'a> {
923927
fn access_level_diagnostic(&mut self, def_id: LocalDefId) {
924-
let span = self.tcx.def_span(def_id.to_def_id());
925928
if self.tcx.has_attr(def_id.to_def_id(), sym::rustc_effective_visibility) {
926-
let mut error_msg = String::new();
927-
928-
let effective_vis =
929-
self.access_levels.get_effective_vis(def_id).copied().unwrap_or_default();
930-
for level in [
931-
AccessLevel::Public,
932-
AccessLevel::Exported,
933-
AccessLevel::Reachable,
934-
AccessLevel::ReachableFromImplTrait,
935-
] {
936-
let vis_str = match effective_vis.get(level) {
937-
Some(ty::Visibility::Restricted(restricted_id)) => {
938-
format!("pub({})", self.tcx.item_name(restricted_id.to_def_id()))
929+
if let Some(effective_vis) = self.access_levels.get_effective_vis(def_id) {
930+
let mut error_msg = String::new();
931+
let span = self.tcx.def_span(def_id.to_def_id());
932+
for level in AccessLevel::all_levels() {
933+
let vis_str = match effective_vis.get(level) {
934+
ty::Visibility::Restricted(restricted_id) => {
935+
if restricted_id.is_top_level_module() {
936+
"pub(crate)".to_string()
937+
} else if *restricted_id == self.tcx.parent_module_from_def_id(def_id) {
938+
"pub(self)".to_string()
939+
} else {
940+
format!("pub({})", self.tcx.item_name(restricted_id.to_def_id()))
941+
}
942+
}
943+
ty::Visibility::Public => "pub".to_string(),
944+
};
945+
if level != AccessLevel::Public {
946+
error_msg.push_str(", ");
939947
}
940-
Some(ty::Visibility::Public) => "pub".to_string(),
941-
None => "pub(self)".to_string(),
942-
};
943-
if level != AccessLevel::Public {
944-
error_msg.push_str(", ");
948+
error_msg.push_str(&format!("{:?}: {}", level, vis_str));
945949
}
946-
error_msg.push_str(&format!("{:?}: {}", level, vis_str));
950+
self.tcx.sess.emit_err(ReportEffectiveVisibility { span, descr: error_msg });
947951
}
948-
self.tcx.sess.emit_err(ReportEffectiveVisibility { span, descr: error_msg });
949952
}
950953
}
951954
}

0 commit comments

Comments
 (0)