Skip to content

Commit 3af17a0

Browse files
Bryanskiypetrochenkov
authored andcommitted
change AccessLevels representation +
1 parent 7098c18 commit 3af17a0

File tree

8 files changed

+293
-136
lines changed

8 files changed

+293
-136
lines changed

compiler/rustc_middle/src/middle/privacy.rs

Lines changed: 128 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
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-
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;
@@ -27,26 +27,148 @@ pub enum AccessLevel {
2727
Public,
2828
}
2929

30+
#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable, Default)]
31+
pub struct EffectiveVisibility {
32+
public: Option<Visibility>,
33+
exported: Option<Visibility>,
34+
reachable: Option<Visibility>,
35+
reachable_from_impl_trait: Option<Visibility>,
36+
}
37+
38+
impl EffectiveVisibility {
39+
fn get_field(&self, tag: AccessLevel) -> &Option<Visibility> {
40+
match tag {
41+
AccessLevel::Public => &self.public,
42+
AccessLevel::Exported => &self.exported,
43+
AccessLevel::Reachable => &self.reachable,
44+
AccessLevel::ReachableFromImplTrait => &self.reachable_from_impl_trait,
45+
}
46+
}
47+
48+
fn get_mut_field(&mut self, tag: AccessLevel) -> &mut Option<Visibility> {
49+
match tag {
50+
AccessLevel::Public => &mut self.public,
51+
AccessLevel::Exported => &mut self.exported,
52+
AccessLevel::Reachable => &mut self.reachable,
53+
AccessLevel::ReachableFromImplTrait => &mut self.reachable_from_impl_trait,
54+
}
55+
}
56+
57+
pub fn get(&self, tag: AccessLevel) -> Option<&Visibility> {
58+
(*self.get_field(tag)).as_ref()
59+
}
60+
61+
fn get_mut(&mut self, tag: AccessLevel) -> Option<&mut Visibility> {
62+
(*self.get_mut_field(tag)).as_mut()
63+
}
64+
65+
fn set(&mut self, effective_vis: Option<Visibility>, tag: AccessLevel) {
66+
*self.get_mut_field(tag) = effective_vis;
67+
}
68+
69+
fn merge(
70+
&mut self,
71+
effective_vis_opt: Option<Visibility>,
72+
tag: AccessLevel,
73+
tree: impl DefIdTree,
74+
) {
75+
let current_effective_vis = self.get_mut(tag);
76+
if let Some(effective_vis) = effective_vis_opt {
77+
if let Some(current_effective_vis) = current_effective_vis {
78+
if current_effective_vis.is_at_least(effective_vis, tree) {
79+
*current_effective_vis = effective_vis;
80+
}
81+
} else {
82+
self.set(effective_vis_opt, tag);
83+
}
84+
}
85+
}
86+
87+
pub fn update(
88+
&mut self,
89+
effective_vis_opt: Option<Visibility>,
90+
tag: AccessLevel,
91+
tree: impl DefIdTree,
92+
) {
93+
for level in [
94+
AccessLevel::Public,
95+
AccessLevel::Exported,
96+
AccessLevel::Reachable,
97+
AccessLevel::ReachableFromImplTrait,
98+
] {
99+
if level <= tag {
100+
self.merge(effective_vis_opt, level, tree);
101+
}
102+
}
103+
}
104+
105+
fn is_public(&self, tag: AccessLevel) -> bool {
106+
self.get(tag).map_or(false, |vis| vis.is_public())
107+
}
108+
}
109+
30110
/// Holds a map of accessibility levels for reachable HIR nodes.
31111
#[derive(Debug, Clone)]
32112
pub struct AccessLevels<Id = LocalDefId> {
33-
pub map: FxHashMap<Id, AccessLevel>,
113+
pub map: FxHashMap<Id, EffectiveVisibility>,
34114
}
35115

36-
impl<Id: Hash + Eq> AccessLevels<Id> {
116+
impl<Id: Hash + Eq + Copy> AccessLevels<Id> {
117+
fn is_smth(&self, id: Id, tag: AccessLevel) -> bool {
118+
self.get_effective_vis(id).map_or(false, |effective_vis| effective_vis.is_public(tag))
119+
}
120+
37121
/// See `AccessLevel::Reachable`.
38122
pub fn is_reachable(&self, id: Id) -> bool {
39-
self.map.get(&id) >= Some(&AccessLevel::Reachable)
123+
self.is_smth(id, AccessLevel::Reachable)
40124
}
41125

42126
/// See `AccessLevel::Exported`.
43127
pub fn is_exported(&self, id: Id) -> bool {
44-
self.map.get(&id) >= Some(&AccessLevel::Exported)
128+
self.is_smth(id, AccessLevel::Exported)
45129
}
46130

47131
/// See `AccessLevel::Public`.
48132
pub fn is_public(&self, id: Id) -> bool {
49-
self.map.get(&id) >= Some(&AccessLevel::Public)
133+
self.is_smth(id, AccessLevel::Public)
134+
}
135+
136+
pub fn get_access_level(&self, id: Id) -> Option<AccessLevel> {
137+
self.get_effective_vis(id).and_then(|effective_vis| {
138+
for level in [
139+
AccessLevel::Public,
140+
AccessLevel::Exported,
141+
AccessLevel::Reachable,
142+
AccessLevel::ReachableFromImplTrait,
143+
] {
144+
if effective_vis.is_public(level) {
145+
return Some(level);
146+
}
147+
}
148+
None
149+
})
150+
}
151+
152+
pub fn set_access_level(
153+
&mut self,
154+
id: Id,
155+
access_level: Option<AccessLevel>,
156+
tree: impl DefIdTree,
157+
) -> Option<AccessLevel> {
158+
if let Some(tag) = access_level {
159+
let mut effective_vis = self.get_effective_vis(id).copied().unwrap_or_default();
160+
effective_vis.update(Some(Visibility::Public), tag, tree);
161+
self.set_effective_vis(id, effective_vis);
162+
}
163+
self.get_access_level(id)
164+
}
165+
166+
pub fn set_effective_vis(&mut self, id: Id, effective_vis: EffectiveVisibility) {
167+
self.map.insert(id, effective_vis);
168+
}
169+
170+
pub fn get_effective_vis(&self, id: Id) -> Option<&EffectiveVisibility> {
171+
self.map.get(&id)
50172
}
51173
}
52174

compiler/rustc_passes/src/dead.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use rustc_hir::def_id::{DefId, LocalDefId};
1111
use rustc_hir::intravisit::{self, Visitor};
1212
use rustc_hir::{Node, PatKind, TyKind};
1313
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
14-
use rustc_middle::middle::privacy;
1514
use rustc_middle::ty::query::Providers;
1615
use rustc_middle::ty::{self, DefIdTree, TyCtxt};
1716
use rustc_session::lint;
@@ -621,11 +620,7 @@ fn create_and_seed_worklist<'tcx>(
621620
let mut worklist = access_levels
622621
.map
623622
.iter()
624-
.filter_map(
625-
|(&id, &level)| {
626-
if level >= privacy::AccessLevel::Reachable { Some(id) } else { None }
627-
},
628-
)
623+
.filter_map(|(&id, _)| if access_levels.is_reachable(id) { Some(id) } else { None })
629624
// Seed entry point
630625
.chain(tcx.entry_fn(()).and_then(|(def_id, _)| def_id.as_local()))
631626
.collect::<Vec<_>>();

compiler/rustc_privacy/src/lib.rs

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ impl VisibilityLike for Option<AccessLevel> {
376376
// (which require reaching the `DefId`s in them).
377377
const SHALLOW: bool = true;
378378
fn new_min(find: &FindMin<'_, '_, Self>, def_id: LocalDefId) -> Self {
379-
cmp::min(find.access_levels.map.get(&def_id).copied(), find.min)
379+
cmp::min(find.access_levels.get_access_level(def_id), find.min)
380380
}
381381
}
382382

@@ -416,7 +416,7 @@ struct ReachEverythingInTheInterfaceVisitor<'a, 'tcx> {
416416

417417
impl<'tcx> EmbargoVisitor<'tcx> {
418418
fn get(&self, def_id: LocalDefId) -> Option<AccessLevel> {
419-
self.access_levels.map.get(&def_id).copied()
419+
self.access_levels.get_access_level(def_id)
420420
}
421421

422422
fn update_with_hir_id(
@@ -433,7 +433,7 @@ 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.map.insert(def_id, level.unwrap());
436+
self.access_levels.set_access_level(def_id, level, self.tcx);
437437
self.changed = true;
438438
level
439439
} else {
@@ -914,10 +914,38 @@ pub struct TestReachabilityVisitor<'tcx, 'a> {
914914

915915
impl<'tcx, 'a> TestReachabilityVisitor<'tcx, 'a> {
916916
fn access_level_diagnostic(&mut self, def_id: LocalDefId) {
917+
let span = self.tcx.def_span(def_id.to_def_id());
917918
if self.tcx.has_attr(def_id.to_def_id(), sym::rustc_access_level) {
918-
let access_level = format!("{:?}", self.access_levels.map.get(&def_id));
919-
let span = self.tcx.def_span(def_id.to_def_id());
920-
self.tcx.sess.emit_err(ReportAccessLevel { span, descr: access_level });
919+
let mut error_msg = String::new();
920+
921+
let effective_vis =
922+
self.access_levels.get_effective_vis(def_id).copied().unwrap_or_default();
923+
let mut process_effective_vis = |tag: AccessLevel| {
924+
let vis = effective_vis.get(tag);
925+
926+
let vis_str = match vis {
927+
Some(ty::Visibility::Restricted(restricted_id)) => {
928+
format!("pub({})", self.tcx.item_name(restricted_id.to_def_id()).as_str())
929+
}
930+
Some(ty::Visibility::Public) => "pub".to_string(),
931+
None => format!("{:?}", vis),
932+
};
933+
if tag != AccessLevel::Public {
934+
error_msg.push(',');
935+
error_msg.push(' ');
936+
}
937+
error_msg.push_str(format!("{:?}: {}", tag, vis_str).as_str());
938+
};
939+
940+
for level in [
941+
AccessLevel::Public,
942+
AccessLevel::Exported,
943+
AccessLevel::Reachable,
944+
AccessLevel::ReachableFromImplTrait,
945+
] {
946+
process_effective_vis(level);
947+
}
948+
self.tcx.sess.emit_err(ReportAccessLevel { span, descr: error_msg });
921949
}
922950
}
923951
}

compiler/rustc_resolve/src/access_levels.rs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use rustc_hir::def_id::LocalDefId;
1212
use rustc_hir::def_id::CRATE_DEF_ID;
1313
use rustc_middle::middle::privacy::AccessLevel;
1414
use rustc_middle::ty::DefIdTree;
15+
use rustc_middle::ty::Visibility;
1516
use rustc_span::sym;
1617

1718
pub struct AccessLevelsVisitor<'r, 'a> {
@@ -46,7 +47,7 @@ impl<'r, 'a> AccessLevelsVisitor<'r, 'a> {
4647
/// This will also follow `use` chains (see PrivacyVisitor::set_import_binding_access_level).
4748
fn set_bindings_access_level(&mut self, module_id: LocalDefId) {
4849
assert!(self.r.module_map.contains_key(&&module_id.to_def_id()));
49-
let module_level = self.r.access_levels.map.get(&module_id).copied();
50+
let module_level = self.r.access_levels.get_access_level(module_id);
5051
if !module_level.is_some() {
5152
return;
5253
}
@@ -103,15 +104,30 @@ impl<'r, 'a> AccessLevelsVisitor<'r, 'a> {
103104
def_id: LocalDefId,
104105
access_level: Option<AccessLevel>,
105106
) -> Option<AccessLevel> {
106-
let old_level = self.r.access_levels.map.get(&def_id).copied();
107+
let old_level = self.r.access_levels.get_access_level(def_id);
107108
if old_level < access_level {
108-
self.r.access_levels.map.insert(def_id, access_level.unwrap());
109+
self.set_access_level_wrapper(def_id, access_level);
109110
self.changed = true;
110111
access_level
111112
} else {
112113
old_level
113114
}
114115
}
116+
117+
fn set_access_level_wrapper(
118+
&mut self,
119+
id: LocalDefId,
120+
access_level: Option<AccessLevel>,
121+
) -> Option<AccessLevel> {
122+
if let Some(tag) = access_level {
123+
let mut effective_vis =
124+
self.r.access_levels.get_effective_vis(id).copied().unwrap_or_default();
125+
126+
effective_vis.update(Some(Visibility::Public), tag, &*self.r);
127+
self.r.access_levels.set_effective_vis(id, effective_vis);
128+
}
129+
self.r.access_levels.get_access_level(id)
130+
}
115131
}
116132

117133
impl<'r, 'ast> Visitor<'ast> for AccessLevelsVisitor<'ast, 'r> {
@@ -131,7 +147,7 @@ impl<'r, 'ast> Visitor<'ast> for AccessLevelsVisitor<'ast, 'r> {
131147
// Foreign modules inherit level from parents.
132148
ast::ItemKind::ForeignMod(..) => {
133149
let parent_level =
134-
self.r.access_levels.map.get(&self.r.local_parent(def_id)).copied();
150+
self.r.access_levels.get_access_level(self.r.local_parent(def_id));
135151
self.set_access_level(item.id, parent_level);
136152
}
137153

@@ -151,15 +167,15 @@ impl<'r, 'ast> Visitor<'ast> for AccessLevelsVisitor<'ast, 'r> {
151167
self.set_bindings_access_level(def_id);
152168
for variant in variants {
153169
let variant_def_id = self.r.local_def_id(variant.id);
154-
let variant_level = self.r.access_levels.map.get(&variant_def_id).copied();
170+
let variant_level = self.r.access_levels.get_access_level(variant_def_id);
155171
for field in variant.data.fields() {
156172
self.set_access_level(field.id, variant_level);
157173
}
158174
}
159175
}
160176

161177
ast::ItemKind::Struct(ref def, _) | ast::ItemKind::Union(ref def, _) => {
162-
let inherited_level = self.r.access_levels.map.get(&def_id).copied();
178+
let inherited_level = self.r.access_levels.get_access_level(def_id);
163179
for field in def.fields() {
164180
if field.vis.kind.is_pub() {
165181
self.set_access_level(field.id, inherited_level);

src/librustdoc/visit_ast.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
230230
} else {
231231
// All items need to be handled here in case someone wishes to link
232232
// to them with intra-doc links
233-
self.cx.cache.access_levels.map.insert(did, AccessLevel::Public);
233+
self.cx.cache.access_levels.set_access_level(
234+
did,
235+
Some(AccessLevel::Public),
236+
self.cx.tcx,
237+
);
234238
}
235239
}
236240
}

src/librustdoc/visit_lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,10 @@ impl<'a, 'tcx> LibEmbargoVisitor<'a, 'tcx> {
3838
fn update(&mut self, did: DefId, level: Option<AccessLevel>) -> Option<AccessLevel> {
3939
let is_hidden = self.tcx.is_doc_hidden(did);
4040

41-
let old_level = self.access_levels.map.get(&did).cloned();
41+
let old_level = self.access_levels.get_access_level(did);
4242
// Accessibility levels can only grow
4343
if level > old_level && !is_hidden {
44-
self.access_levels.map.insert(did, level.unwrap());
44+
self.access_levels.set_access_level(did, level, self.tcx);
4545
level
4646
} else {
4747
old_level

0 commit comments

Comments
 (0)