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:: { DefIdTree , Visibility } ;
4+ use crate :: ty:: { DefIdTree , TyCtxt , Visibility } ;
55use rustc_data_structures:: fx:: FxHashMap ;
66use rustc_data_structures:: stable_hasher:: { HashStable , StableHasher } ;
7+ use rustc_hir:: def:: DefKind ;
78use rustc_macros:: HashStable ;
89use rustc_query_system:: ich:: StableHashingContext ;
910use rustc_span:: def_id:: LocalDefId ;
11+ use std:: hash:: Hash ;
1012
1113/// Represents the levels of effective visibility an item can have.
1214///
@@ -74,9 +76,9 @@ impl EffectiveVisibility {
7476}
7577
7678/// 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 > ,
8082}
8183
8284impl EffectiveVisibilities {
@@ -111,12 +113,30 @@ impl EffectiveVisibilities {
111113 } )
112114 }
113115
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+ } ;
120140 }
121141
122142 pub fn set_public_at_level (
@@ -137,26 +157,82 @@ impl EffectiveVisibilities {
137157 self . map . insert ( id, effective_vis) ;
138158 }
139159
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+
140218 // `parent_id` is not necessarily a parent in source code tree,
141219 // it is the node from which the maximum effective visibility is inherited.
142220 pub fn update (
143221 & mut self ,
144- id : LocalDefId ,
222+ id : Id ,
145223 nominal_vis : Visibility ,
146- default_vis : impl FnOnce ( ) -> Visibility ,
147- parent_id : LocalDefId ,
224+ default_vis : Visibility ,
225+ inherited_eff_vis : Option < EffectiveVisibility > ,
148226 level : Level ,
149227 tree : impl DefIdTree ,
150228 ) -> bool {
151229 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 {
160236 let mut inherited_effective_vis_at_prev_level =
161237 * inherited_effective_vis. at_level ( level) ;
162238 let mut calculated_effective_vis = inherited_effective_vis_at_prev_level;
@@ -194,6 +270,12 @@ impl EffectiveVisibilities {
194270 }
195271}
196272
273+ impl < Id > Default for EffectiveVisibilities < Id > {
274+ fn default ( ) -> Self {
275+ EffectiveVisibilities { map : Default :: default ( ) }
276+ }
277+ }
278+
197279impl < ' a > HashStable < StableHashingContext < ' a > > for EffectiveVisibilities {
198280 fn hash_stable ( & self , hcx : & mut StableHashingContext < ' a > , hasher : & mut StableHasher ) {
199281 let EffectiveVisibilities { ref map } = * self ;
0 commit comments