1
1
//! A pass that checks to make sure private fields and methods aren't used
2
2
//! outside their scopes. This pass will also generate a set of exported items
3
3
//! which are available for use externally when compiled as a library.
4
- use crate :: ty:: { DefIdTree , Visibility } ;
4
+ use crate :: ty:: { DefIdTree , TyCtxt , Visibility } ;
5
5
use rustc_data_structures:: fx:: FxHashMap ;
6
6
use rustc_data_structures:: stable_hasher:: { HashStable , StableHasher } ;
7
+ use rustc_hir:: def:: DefKind ;
7
8
use rustc_macros:: HashStable ;
8
9
use rustc_query_system:: ich:: StableHashingContext ;
9
10
use rustc_span:: def_id:: LocalDefId ;
11
+ use std:: hash:: Hash ;
10
12
11
13
/// Represents the levels of effective visibility an item can have.
12
14
///
@@ -74,9 +76,9 @@ impl EffectiveVisibility {
74
76
}
75
77
76
78
/// Holds a map of effective visibilities for reachable HIR nodes.
77
- #[ derive( Default , Clone , Debug ) ]
78
- pub struct EffectiveVisibilities {
79
- map : FxHashMap < LocalDefId , EffectiveVisibility > ,
79
+ #[ derive( Clone , Debug ) ]
80
+ pub struct EffectiveVisibilities < Id = LocalDefId > {
81
+ map : FxHashMap < Id , EffectiveVisibility > ,
80
82
}
81
83
82
84
impl EffectiveVisibilities {
@@ -111,12 +113,30 @@ impl EffectiveVisibilities {
111
113
} )
112
114
}
113
115
114
- pub fn effective_vis ( & self , id : LocalDefId ) -> Option < & EffectiveVisibility > {
115
- self . map . get ( & id)
116
- }
117
-
118
- pub fn iter ( & self ) -> impl Iterator < Item = ( & LocalDefId , & EffectiveVisibility ) > {
119
- self . map . iter ( )
116
+ // FIXME: Share code with `fn update`.
117
+ pub fn update_eff_vis (
118
+ & mut self ,
119
+ def_id : LocalDefId ,
120
+ eff_vis : & EffectiveVisibility ,
121
+ tree : impl DefIdTree ,
122
+ ) {
123
+ use std:: collections:: hash_map:: Entry ;
124
+ match self . map . entry ( def_id) {
125
+ Entry :: Occupied ( mut occupied) => {
126
+ let old_eff_vis = occupied. get_mut ( ) ;
127
+ for l in Level :: all_levels ( ) {
128
+ let vis_at_level = eff_vis. at_level ( l) ;
129
+ let old_vis_at_level = old_eff_vis. at_level_mut ( l) ;
130
+ if vis_at_level != old_vis_at_level
131
+ && vis_at_level. is_at_least ( * old_vis_at_level, tree)
132
+ {
133
+ * old_vis_at_level = * vis_at_level
134
+ }
135
+ }
136
+ old_eff_vis
137
+ }
138
+ Entry :: Vacant ( vacant) => vacant. insert ( * eff_vis) ,
139
+ } ;
120
140
}
121
141
122
142
pub fn set_public_at_level (
@@ -137,26 +157,82 @@ impl EffectiveVisibilities {
137
157
self . map . insert ( id, effective_vis) ;
138
158
}
139
159
160
+ pub fn check_invariants ( & self , tcx : TyCtxt < ' _ > , early : bool ) {
161
+ if !cfg ! ( debug_assertions) {
162
+ return ;
163
+ }
164
+ for ( & def_id, ev) in & self . map {
165
+ // More direct visibility levels can never go farther than less direct ones,
166
+ // neither of effective visibilities can go farther than nominal visibility,
167
+ // and all effective visibilities are larger or equal than private visibility.
168
+ let private_vis = Visibility :: Restricted ( tcx. parent_module_from_def_id ( def_id) ) ;
169
+ let span = tcx. def_span ( def_id. to_def_id ( ) ) ;
170
+ if !ev. direct . is_at_least ( private_vis, tcx) {
171
+ span_bug ! ( span, "private {:?} > direct {:?}" , private_vis, ev. direct) ;
172
+ }
173
+ if !ev. reexported . is_at_least ( ev. direct , tcx) {
174
+ span_bug ! ( span, "direct {:?} > reexported {:?}" , ev. direct, ev. reexported) ;
175
+ }
176
+ if !ev. reachable . is_at_least ( ev. reexported , tcx) {
177
+ span_bug ! ( span, "reexported {:?} > reachable {:?}" , ev. reexported, ev. reachable) ;
178
+ }
179
+ if !ev. reachable_through_impl_trait . is_at_least ( ev. reachable , tcx) {
180
+ span_bug ! (
181
+ span,
182
+ "reachable {:?} > reachable_through_impl_trait {:?}" ,
183
+ ev. reachable,
184
+ ev. reachable_through_impl_trait
185
+ ) ;
186
+ }
187
+ let nominal_vis = tcx. visibility ( def_id) ;
188
+ let def_kind = tcx. opt_def_kind ( def_id) ;
189
+ // FIXME: `rustc_privacy` is not yet updated for the new logic and can set
190
+ // effective visibilities that are larger than the nominal one.
191
+ if !nominal_vis. is_at_least ( ev. reachable_through_impl_trait , tcx) && early {
192
+ span_bug ! (
193
+ span,
194
+ "{:?}: reachable_through_impl_trait {:?} > nominal {:?}" ,
195
+ def_id,
196
+ ev. reachable_through_impl_trait,
197
+ nominal_vis
198
+ ) ;
199
+ }
200
+ // Fully private items are never put into the table, this is important for performance.
201
+ // FIXME: Fully private `mod` items are currently put into the table.
202
+ if ev. reachable_through_impl_trait == private_vis && def_kind != Some ( DefKind :: Mod ) {
203
+ span_bug ! ( span, "fully private item in the table {:?}: {:?}" , def_id, ev. direct) ;
204
+ }
205
+ }
206
+ }
207
+ }
208
+
209
+ impl < Id : Eq + Hash > EffectiveVisibilities < Id > {
210
+ pub fn iter ( & self ) -> impl Iterator < Item = ( & Id , & EffectiveVisibility ) > {
211
+ self . map . iter ( )
212
+ }
213
+
214
+ pub fn effective_vis ( & self , id : Id ) -> Option < & EffectiveVisibility > {
215
+ self . map . get ( & id)
216
+ }
217
+
140
218
// `parent_id` is not necessarily a parent in source code tree,
141
219
// it is the node from which the maximum effective visibility is inherited.
142
220
pub fn update (
143
221
& mut self ,
144
- id : LocalDefId ,
222
+ id : Id ,
145
223
nominal_vis : Visibility ,
146
- default_vis : impl FnOnce ( ) -> Visibility ,
147
- parent_id : LocalDefId ,
224
+ default_vis : Visibility ,
225
+ inherited_eff_vis : Option < EffectiveVisibility > ,
148
226
level : Level ,
149
227
tree : impl DefIdTree ,
150
228
) -> bool {
151
229
let mut changed = false ;
152
- let mut current_effective_vis = self . effective_vis ( id) . copied ( ) . unwrap_or_else ( || {
153
- if id. is_top_level_module ( ) {
154
- EffectiveVisibility :: from_vis ( Visibility :: Public )
155
- } else {
156
- EffectiveVisibility :: from_vis ( default_vis ( ) )
157
- }
158
- } ) ;
159
- if let Some ( inherited_effective_vis) = self . effective_vis ( parent_id) {
230
+ let mut current_effective_vis = self
231
+ . map
232
+ . get ( & id)
233
+ . copied ( )
234
+ . unwrap_or_else ( || EffectiveVisibility :: from_vis ( default_vis) ) ;
235
+ if let Some ( inherited_effective_vis) = inherited_eff_vis {
160
236
let mut inherited_effective_vis_at_prev_level =
161
237
* inherited_effective_vis. at_level ( level) ;
162
238
let mut calculated_effective_vis = inherited_effective_vis_at_prev_level;
@@ -194,6 +270,12 @@ impl EffectiveVisibilities {
194
270
}
195
271
}
196
272
273
+ impl < Id > Default for EffectiveVisibilities < Id > {
274
+ fn default ( ) -> Self {
275
+ EffectiveVisibilities { map : Default :: default ( ) }
276
+ }
277
+ }
278
+
197
279
impl < ' a > HashStable < StableHashingContext < ' a > > for EffectiveVisibilities {
198
280
fn hash_stable ( & self , hcx : & mut StableHashingContext < ' a > , hasher : & mut StableHasher ) {
199
281
let EffectiveVisibilities { ref map } = * self ;
0 commit comments