|
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;
|
@@ -133,6 +134,54 @@ impl EffectiveVisibilities {
|
133 | 134 | }
|
134 | 135 | self.map.insert(id, effective_vis);
|
135 | 136 | }
|
| 137 | + |
| 138 | + pub fn check_invariants(&self, tcx: TyCtxt<'_>, early: bool) { |
| 139 | + if !cfg!(debug_assertions) { |
| 140 | + return; |
| 141 | + } |
| 142 | + for (&def_id, ev) in &self.map { |
| 143 | + // More direct visibility levels can never go farther than less direct ones, |
| 144 | + // neither of effective visibilities can go farther than nominal visibility, |
| 145 | + // and all effective visibilities are larger or equal than private visibility. |
| 146 | + let private_vis = Visibility::Restricted(tcx.parent_module_from_def_id(def_id)); |
| 147 | + let span = tcx.def_span(def_id.to_def_id()); |
| 148 | + if !ev.direct.is_at_least(private_vis, tcx) { |
| 149 | + span_bug!(span, "private {:?} > direct {:?}", private_vis, ev.direct); |
| 150 | + } |
| 151 | + if !ev.reexported.is_at_least(ev.direct, tcx) { |
| 152 | + span_bug!(span, "direct {:?} > reexported {:?}", ev.direct, ev.reexported); |
| 153 | + } |
| 154 | + if !ev.reachable.is_at_least(ev.reexported, tcx) { |
| 155 | + span_bug!(span, "reexported {:?} > reachable {:?}", ev.reexported, ev.reachable); |
| 156 | + } |
| 157 | + if !ev.reachable_through_impl_trait.is_at_least(ev.reachable, tcx) { |
| 158 | + span_bug!( |
| 159 | + span, |
| 160 | + "reachable {:?} > reachable_through_impl_trait {:?}", |
| 161 | + ev.reachable, |
| 162 | + ev.reachable_through_impl_trait |
| 163 | + ); |
| 164 | + } |
| 165 | + let nominal_vis = tcx.visibility(def_id); |
| 166 | + let def_kind = tcx.opt_def_kind(def_id); |
| 167 | + // FIXME: `rustc_privacy` is not yet updated for the new logic and can set |
| 168 | + // effective visibilities that are larger than the nominal one. |
| 169 | + if !nominal_vis.is_at_least(ev.reachable_through_impl_trait, tcx) && early { |
| 170 | + span_bug!( |
| 171 | + span, |
| 172 | + "{:?}: reachable_through_impl_trait {:?} > nominal {:?}", |
| 173 | + def_id, |
| 174 | + ev.reachable_through_impl_trait, |
| 175 | + nominal_vis |
| 176 | + ); |
| 177 | + } |
| 178 | + // Fully private items are never put into the table, this is important for performance. |
| 179 | + // FIXME: Fully private `mod` items are currently put into the table. |
| 180 | + if ev.reachable_through_impl_trait == private_vis && def_kind != Some(DefKind::Mod) { |
| 181 | + span_bug!(span, "fully private item in the table {:?}: {:?}", def_id, ev.direct); |
| 182 | + } |
| 183 | + } |
| 184 | + } |
136 | 185 | }
|
137 | 186 |
|
138 | 187 | impl<Id: Eq + Hash> EffectiveVisibilities<Id> {
|
|
0 commit comments