]>
Commit | Line | Data |
---|---|---|
1b1a35ee | 1 | #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] |
064997fb | 2 | #![feature(associated_type_defaults)] |
29967ef6 | 3 | #![feature(control_flow_enum)] |
064997fb | 4 | #![feature(rustc_private)] |
29967ef6 | 5 | #![feature(try_blocks)] |
dfeec247 | 6 | #![recursion_limit = "256"] |
f2b60f7d FG |
7 | #![deny(rustc::untranslatable_diagnostic)] |
8 | #![deny(rustc::diagnostic_outside_of_impl)] | |
9 | ||
10 | #[macro_use] | |
11 | extern crate tracing; | |
064997fb FG |
12 | |
13 | mod errors; | |
e9174d1e | 14 | |
94222f64 | 15 | use rustc_ast::MacroDef; |
74b04a01 | 16 | use rustc_attr as attr; |
0731742a | 17 | use rustc_data_structures::fx::FxHashSet; |
5e7ed085 | 18 | use rustc_data_structures::intern::Interned; |
dfeec247 XL |
19 | use rustc_hir as hir; |
20 | use rustc_hir::def::{DefKind, Res}; | |
5099ac24 | 21 | use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID}; |
923072b8 FG |
22 | use rustc_hir::intravisit::{self, Visitor}; |
23 | use rustc_hir::{AssocItemKind, HirIdSet, ItemId, Node, PatKind}; | |
ba9703b0 | 24 | use rustc_middle::bug; |
5099ac24 | 25 | use rustc_middle::hir::nested_filter; |
2b03887a | 26 | use rustc_middle::middle::privacy::{EffectiveVisibilities, Level}; |
29967ef6 | 27 | use rustc_middle::span_bug; |
064997fb | 28 | use rustc_middle::ty::abstract_const::{walk_abstract_const, AbstractConst, Node as ACNode}; |
ba9703b0 | 29 | use rustc_middle::ty::query::Providers; |
3c0e092e | 30 | use rustc_middle::ty::subst::InternalSubsts; |
04454e1e | 31 | use rustc_middle::ty::{self, Const, DefIdTree, GenericParamDefKind}; |
064997fb | 32 | use rustc_middle::ty::{TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; |
ba9703b0 | 33 | use rustc_session::lint; |
dfeec247 | 34 | use rustc_span::hygiene::Transparency; |
f2b60f7d | 35 | use rustc_span::symbol::{kw, sym, Ident}; |
dfeec247 | 36 | use rustc_span::Span; |
85aaf69f | 37 | |
0731742a | 38 | use std::marker::PhantomData; |
29967ef6 | 39 | use std::ops::ControlFlow; |
dfeec247 | 40 | use std::{cmp, fmt, mem}; |
85aaf69f | 41 | |
064997fb FG |
42 | use errors::{ |
43 | FieldIsPrivate, FieldIsPrivateLabel, FromPrivateDependencyInPublicInterface, InPublicInterface, | |
2b03887a | 44 | InPublicInterfaceTraits, ItemIsPrivate, PrivateInPublicLint, ReportEffectiveVisibility, |
f2b60f7d | 45 | UnnamedItemIsPrivate, |
064997fb FG |
46 | }; |
47 | ||
0731742a XL |
48 | //////////////////////////////////////////////////////////////////////////////// |
49 | /// Generic infrastructure used to implement specific visitors below. | |
50 | //////////////////////////////////////////////////////////////////////////////// | |
51 | ||
52 | /// Implemented to visit all `DefId`s in a type. | |
53 | /// Visiting `DefId`s is useful because visibilities and reachabilities are attached to them. | |
54 | /// The idea is to visit "all components of a type", as documented in | |
29967ef6 | 55 | /// <https://github.com/rust-lang/rfcs/blob/master/text/2145-type-privacy.md#how-to-determine-visibility-of-a-type>. |
9fa01778 XL |
56 | /// The default type visitor (`TypeVisitor`) does most of the job, but it has some shortcomings. |
57 | /// First, it doesn't have overridable `fn visit_trait_ref`, so we have to catch trait `DefId`s | |
0731742a XL |
58 | /// manually. Second, it doesn't visit some type components like signatures of fn types, or traits |
59 | /// in `impl Trait`, see individual comments in `DefIdVisitorSkeleton::visit_ty`. | |
dc9dc135 | 60 | trait DefIdVisitor<'tcx> { |
fc512014 XL |
61 | type BreakTy = (); |
62 | ||
dc9dc135 | 63 | fn tcx(&self) -> TyCtxt<'tcx>; |
dfeec247 XL |
64 | fn shallow(&self) -> bool { |
65 | false | |
66 | } | |
67 | fn skip_assoc_tys(&self) -> bool { | |
68 | false | |
69 | } | |
29967ef6 XL |
70 | fn visit_def_id( |
71 | &mut self, | |
72 | def_id: DefId, | |
73 | kind: &str, | |
74 | descr: &dyn fmt::Display, | |
fc512014 | 75 | ) -> ControlFlow<Self::BreakTy>; |
0731742a XL |
76 | |
77 | /// Not overridden, but used to actually visit types and traits. | |
dc9dc135 | 78 | fn skeleton(&mut self) -> DefIdVisitorSkeleton<'_, 'tcx, Self> { |
0731742a XL |
79 | DefIdVisitorSkeleton { |
80 | def_id_visitor: self, | |
81 | visited_opaque_tys: Default::default(), | |
82 | dummy: Default::default(), | |
83 | } | |
84 | } | |
064997fb | 85 | fn visit(&mut self, ty_fragment: impl TypeVisitable<'tcx>) -> ControlFlow<Self::BreakTy> { |
0731742a XL |
86 | ty_fragment.visit_with(&mut self.skeleton()) |
87 | } | |
fc512014 | 88 | fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<Self::BreakTy> { |
0731742a XL |
89 | self.skeleton().visit_trait(trait_ref) |
90 | } | |
6a06907d XL |
91 | fn visit_projection_ty( |
92 | &mut self, | |
93 | projection: ty::ProjectionTy<'tcx>, | |
94 | ) -> ControlFlow<Self::BreakTy> { | |
95 | self.skeleton().visit_projection_ty(projection) | |
96 | } | |
fc512014 XL |
97 | fn visit_predicates( |
98 | &mut self, | |
99 | predicates: ty::GenericPredicates<'tcx>, | |
100 | ) -> ControlFlow<Self::BreakTy> { | |
0731742a XL |
101 | self.skeleton().visit_predicates(predicates) |
102 | } | |
103 | } | |
104 | ||
3dfed10e | 105 | struct DefIdVisitorSkeleton<'v, 'tcx, V: ?Sized> { |
0731742a XL |
106 | def_id_visitor: &'v mut V, |
107 | visited_opaque_tys: FxHashSet<DefId>, | |
dc9dc135 | 108 | dummy: PhantomData<TyCtxt<'tcx>>, |
0731742a XL |
109 | } |
110 | ||
dc9dc135 XL |
111 | impl<'tcx, V> DefIdVisitorSkeleton<'_, 'tcx, V> |
112 | where | |
113 | V: DefIdVisitor<'tcx> + ?Sized, | |
0731742a | 114 | { |
fc512014 | 115 | fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<V::BreakTy> { |
0731742a | 116 | let TraitRef { def_id, substs } = trait_ref; |
29967ef6 XL |
117 | self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref.print_only_trait_path())?; |
118 | if self.def_id_visitor.shallow() { ControlFlow::CONTINUE } else { substs.visit_with(self) } | |
0731742a XL |
119 | } |
120 | ||
6a06907d XL |
121 | fn visit_projection_ty( |
122 | &mut self, | |
123 | projection: ty::ProjectionTy<'tcx>, | |
124 | ) -> ControlFlow<V::BreakTy> { | |
2b03887a FG |
125 | let tcx = self.def_id_visitor.tcx(); |
126 | let (trait_ref, assoc_substs) = if tcx.def_kind(projection.item_def_id) | |
127 | != DefKind::ImplTraitPlaceholder | |
128 | { | |
129 | projection.trait_ref_and_own_substs(tcx) | |
130 | } else { | |
131 | // HACK(RPITIT): Remove this when RPITITs are lowered to regular assoc tys | |
132 | let def_id = tcx.impl_trait_in_trait_parent(projection.item_def_id); | |
133 | let trait_generics = tcx.generics_of(def_id); | |
134 | ( | |
135 | ty::TraitRef { def_id, substs: projection.substs.truncate_to(tcx, trait_generics) }, | |
136 | &projection.substs[trait_generics.count()..], | |
137 | ) | |
138 | }; | |
6a06907d XL |
139 | self.visit_trait(trait_ref)?; |
140 | if self.def_id_visitor.shallow() { | |
141 | ControlFlow::CONTINUE | |
142 | } else { | |
143 | assoc_substs.iter().try_for_each(|subst| subst.visit_with(self)) | |
144 | } | |
145 | } | |
146 | ||
fc512014 | 147 | fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<V::BreakTy> { |
5869c6ff | 148 | match predicate.kind().skip_binder() { |
3c0e092e XL |
149 | ty::PredicateKind::Trait(ty::TraitPredicate { |
150 | trait_ref, | |
151 | constness: _, | |
152 | polarity: _, | |
153 | }) => self.visit_trait(trait_ref), | |
5099ac24 FG |
154 | ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => { |
155 | term.visit_with(self)?; | |
6a06907d | 156 | self.visit_projection_ty(projection_ty) |
3dfed10e | 157 | } |
5869c6ff | 158 | ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _region)) => { |
3dfed10e XL |
159 | ty.visit_with(self) |
160 | } | |
5869c6ff | 161 | ty::PredicateKind::RegionOutlives(..) => ControlFlow::CONTINUE, |
2b03887a | 162 | ty::PredicateKind::ConstEvaluatable(ct) => ct.visit_with(self), |
064997fb | 163 | ty::PredicateKind::WellFormed(arg) => arg.visit_with(self), |
3dfed10e XL |
164 | _ => bug!("unexpected predicate: {:?}", predicate), |
165 | } | |
166 | } | |
167 | ||
fc512014 XL |
168 | fn visit_predicates( |
169 | &mut self, | |
170 | predicates: ty::GenericPredicates<'tcx>, | |
171 | ) -> ControlFlow<V::BreakTy> { | |
dc9dc135 | 172 | let ty::GenericPredicates { parent: _, predicates } = predicates; |
29967ef6 | 173 | predicates.iter().try_for_each(|&(predicate, _span)| self.visit_predicate(predicate)) |
0731742a XL |
174 | } |
175 | } | |
176 | ||
dc9dc135 XL |
177 | impl<'tcx, V> TypeVisitor<'tcx> for DefIdVisitorSkeleton<'_, 'tcx, V> |
178 | where | |
179 | V: DefIdVisitor<'tcx> + ?Sized, | |
0731742a | 180 | { |
fc512014 XL |
181 | type BreakTy = V::BreakTy; |
182 | ||
183 | fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<V::BreakTy> { | |
0731742a | 184 | let tcx = self.def_id_visitor.tcx(); |
923072b8 FG |
185 | // InternalSubsts are not visited here because they are visited below |
186 | // in `super_visit_with`. | |
1b1a35ee | 187 | match *ty.kind() { |
5e7ed085 | 188 | ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), ..) |
dfeec247 XL |
189 | | ty::Foreign(def_id) |
190 | | ty::FnDef(def_id, ..) | |
191 | | ty::Closure(def_id, ..) | |
192 | | ty::Generator(def_id, ..) => { | |
29967ef6 | 193 | self.def_id_visitor.visit_def_id(def_id, "type", &ty)?; |
0731742a | 194 | if self.def_id_visitor.shallow() { |
29967ef6 | 195 | return ControlFlow::CONTINUE; |
0731742a XL |
196 | } |
197 | // Default type visitor doesn't visit signatures of fn types. | |
198 | // Something like `fn() -> Priv {my_func}` is considered a private type even if | |
199 | // `my_func` is public, so we need to visit signatures. | |
1b1a35ee | 200 | if let ty::FnDef(..) = ty.kind() { |
29967ef6 | 201 | tcx.fn_sig(def_id).visit_with(self)?; |
0731742a XL |
202 | } |
203 | // Inherent static methods don't have self type in substs. | |
204 | // Something like `fn() {my_method}` type of the method | |
205 | // `impl Pub<Priv> { pub fn my_method() {} }` is considered a private type, | |
206 | // so we need to visit the self type additionally. | |
207 | if let Some(assoc_item) = tcx.opt_associated_item(def_id) { | |
064997fb | 208 | if let Some(impl_def_id) = assoc_item.impl_container(tcx) { |
29967ef6 | 209 | tcx.type_of(impl_def_id).visit_with(self)?; |
0731742a XL |
210 | } |
211 | } | |
212 | } | |
f9f354fc | 213 | ty::Projection(proj) => { |
0731742a XL |
214 | if self.def_id_visitor.skip_assoc_tys() { |
215 | // Visitors searching for minimal visibility/reachability want to | |
216 | // conservatively approximate associated types like `<Type as Trait>::Alias` | |
217 | // as visible/reachable even if both `Type` and `Trait` are private. | |
218 | // Ideally, associated types should be substituted in the same way as | |
219 | // free type aliases, but this isn't done yet. | |
29967ef6 | 220 | return ControlFlow::CONTINUE; |
0731742a XL |
221 | } |
222 | // This will also visit substs if necessary, so we don't need to recurse. | |
6a06907d | 223 | return self.visit_projection_ty(proj); |
0731742a XL |
224 | } |
225 | ty::Dynamic(predicates, ..) => { | |
226 | // All traits in the list are considered the "primary" part of the type | |
227 | // and are visited by shallow visitors. | |
fc512014 XL |
228 | for predicate in predicates { |
229 | let trait_ref = match predicate.skip_binder() { | |
0731742a XL |
230 | ty::ExistentialPredicate::Trait(trait_ref) => trait_ref, |
231 | ty::ExistentialPredicate::Projection(proj) => proj.trait_ref(tcx), | |
dfeec247 XL |
232 | ty::ExistentialPredicate::AutoTrait(def_id) => { |
233 | ty::ExistentialTraitRef { def_id, substs: InternalSubsts::empty() } | |
234 | } | |
0731742a XL |
235 | }; |
236 | let ty::ExistentialTraitRef { def_id, substs: _ } = trait_ref; | |
29967ef6 | 237 | self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref)?; |
0731742a XL |
238 | } |
239 | } | |
240 | ty::Opaque(def_id, ..) => { | |
241 | // Skip repeated `Opaque`s to avoid infinite recursion. | |
242 | if self.visited_opaque_tys.insert(def_id) { | |
243 | // The intent is to treat `impl Trait1 + Trait2` identically to | |
244 | // `dyn Trait1 + Trait2`. Therefore we ignore def-id of the opaque type itself | |
245 | // (it either has no visibility, or its visibility is insignificant, like | |
29967ef6 | 246 | // visibilities of type aliases) and recurse into bounds instead to go |
0731742a XL |
247 | // through the trait list (default type visitor doesn't visit those traits). |
248 | // All traits in the list are considered the "primary" part of the type | |
249 | // and are visited by shallow visitors. | |
29967ef6 XL |
250 | self.visit_predicates(ty::GenericPredicates { |
251 | parent: None, | |
252 | predicates: tcx.explicit_item_bounds(def_id), | |
253 | })?; | |
0731742a XL |
254 | } |
255 | } | |
256 | // These types don't have their own def-ids (but may have subcomponents | |
257 | // with def-ids that should be visited recursively). | |
dfeec247 XL |
258 | ty::Bool |
259 | | ty::Char | |
260 | | ty::Int(..) | |
261 | | ty::Uint(..) | |
262 | | ty::Float(..) | |
263 | | ty::Str | |
264 | | ty::Never | |
265 | | ty::Array(..) | |
266 | | ty::Slice(..) | |
267 | | ty::Tuple(..) | |
268 | | ty::RawPtr(..) | |
269 | | ty::Ref(..) | |
270 | | ty::FnPtr(..) | |
271 | | ty::Param(..) | |
f035d41b | 272 | | ty::Error(_) |
dfeec247 XL |
273 | | ty::GeneratorWitness(..) => {} |
274 | ty::Bound(..) | ty::Placeholder(..) | ty::Infer(..) => { | |
275 | bug!("unexpected type: {:?}", ty) | |
276 | } | |
0731742a XL |
277 | } |
278 | ||
29967ef6 XL |
279 | if self.def_id_visitor.shallow() { |
280 | ControlFlow::CONTINUE | |
281 | } else { | |
282 | ty.super_visit_with(self) | |
0731742a XL |
283 | } |
284 | } | |
5869c6ff | 285 | |
5099ac24 FG |
286 | fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> { |
287 | self.visit_ty(c.ty())?; | |
5869c6ff XL |
288 | let tcx = self.def_id_visitor.tcx(); |
289 | if let Ok(Some(ct)) = AbstractConst::from_const(tcx, c) { | |
2b03887a FG |
290 | walk_abstract_const(tcx, ct, |node| match node.root(tcx) { |
291 | ACNode::Leaf(leaf) => self.visit_const(leaf), | |
292 | ACNode::Cast(_, _, ty) => self.visit_ty(ty), | |
293 | ACNode::Binop(..) | ACNode::UnaryOp(..) | ACNode::FunctionCall(_, _) => { | |
294 | ControlFlow::CONTINUE | |
295 | } | |
296 | }) | |
297 | } else { | |
298 | ControlFlow::CONTINUE | |
5869c6ff | 299 | } |
5869c6ff | 300 | } |
0731742a XL |
301 | } |
302 | ||
416331ca | 303 | fn min(vis1: ty::Visibility, vis2: ty::Visibility, tcx: TyCtxt<'_>) -> ty::Visibility { |
0731742a XL |
304 | if vis1.is_at_least(vis2, tcx) { vis2 } else { vis1 } |
305 | } | |
306 | ||
0731742a XL |
307 | //////////////////////////////////////////////////////////////////////////////// |
308 | /// Visitor used to determine impl visibility and reachability. | |
309 | //////////////////////////////////////////////////////////////////////////////// | |
310 | ||
311 | struct FindMin<'a, 'tcx, VL: VisibilityLike> { | |
dc9dc135 | 312 | tcx: TyCtxt<'tcx>, |
2b03887a | 313 | effective_visibilities: &'a EffectiveVisibilities, |
0731742a XL |
314 | min: VL, |
315 | } | |
316 | ||
dc9dc135 | 317 | impl<'a, 'tcx, VL: VisibilityLike> DefIdVisitor<'tcx> for FindMin<'a, 'tcx, VL> { |
dfeec247 XL |
318 | fn tcx(&self) -> TyCtxt<'tcx> { |
319 | self.tcx | |
320 | } | |
321 | fn shallow(&self) -> bool { | |
322 | VL::SHALLOW | |
323 | } | |
324 | fn skip_assoc_tys(&self) -> bool { | |
325 | true | |
326 | } | |
29967ef6 XL |
327 | fn visit_def_id( |
328 | &mut self, | |
329 | def_id: DefId, | |
330 | _kind: &str, | |
331 | _descr: &dyn fmt::Display, | |
fc512014 | 332 | ) -> ControlFlow<Self::BreakTy> { |
f2b60f7d FG |
333 | if let Some(def_id) = def_id.as_local() { |
334 | self.min = VL::new_min(self, def_id); | |
335 | } | |
29967ef6 | 336 | ControlFlow::CONTINUE |
0731742a XL |
337 | } |
338 | } | |
339 | ||
340 | trait VisibilityLike: Sized { | |
341 | const MAX: Self; | |
342 | const SHALLOW: bool = false; | |
f2b60f7d | 343 | fn new_min(find: &FindMin<'_, '_, Self>, def_id: LocalDefId) -> Self; |
0731742a XL |
344 | |
345 | // Returns an over-approximation (`skip_assoc_tys` = true) of visibility due to | |
346 | // associated types for which we can't determine visibility precisely. | |
2b03887a FG |
347 | fn of_impl( |
348 | def_id: LocalDefId, | |
349 | tcx: TyCtxt<'_>, | |
350 | effective_visibilities: &EffectiveVisibilities, | |
351 | ) -> Self { | |
352 | let mut find = FindMin { tcx, effective_visibilities, min: Self::MAX }; | |
0731742a XL |
353 | find.visit(tcx.type_of(def_id)); |
354 | if let Some(trait_ref) = tcx.impl_trait_ref(def_id) { | |
355 | find.visit_trait(trait_ref); | |
356 | } | |
357 | find.min | |
358 | } | |
359 | } | |
360 | impl VisibilityLike for ty::Visibility { | |
361 | const MAX: Self = ty::Visibility::Public; | |
f2b60f7d FG |
362 | fn new_min(find: &FindMin<'_, '_, Self>, def_id: LocalDefId) -> Self { |
363 | min(find.tcx.local_visibility(def_id), find.min, find.tcx) | |
0731742a XL |
364 | } |
365 | } | |
2b03887a FG |
366 | impl VisibilityLike for Option<Level> { |
367 | const MAX: Self = Some(Level::Direct); | |
0731742a XL |
368 | // Type inference is very smart sometimes. |
369 | // It can make an impl reachable even some components of its type or trait are unreachable. | |
370 | // E.g. methods of `impl ReachableTrait<UnreachableTy> for ReachableTy<UnreachableTy> { ... }` | |
371 | // can be usable from other crates (#57264). So we skip substs when calculating reachability | |
372 | // and consider an impl reachable if its "shallow" type and trait are reachable. | |
373 | // | |
374 | // The assumption we make here is that type-inference won't let you use an impl without knowing | |
375 | // both "shallow" version of its self type and "shallow" version of its trait if it exists | |
376 | // (which require reaching the `DefId`s in them). | |
377 | const SHALLOW: bool = true; | |
f2b60f7d | 378 | fn new_min(find: &FindMin<'_, '_, Self>, def_id: LocalDefId) -> Self { |
2b03887a | 379 | cmp::min(find.effective_visibilities.public_at_level(def_id), find.min) |
0731742a XL |
380 | } |
381 | } | |
382 | ||
85aaf69f | 383 | //////////////////////////////////////////////////////////////////////////////// |
9fa01778 | 384 | /// The embargo visitor, used to determine the exports of the AST. |
85aaf69f SL |
385 | //////////////////////////////////////////////////////////////////////////////// |
386 | ||
dc9dc135 XL |
387 | struct EmbargoVisitor<'tcx> { |
388 | tcx: TyCtxt<'tcx>, | |
85aaf69f | 389 | |
2b03887a FG |
390 | /// Effective visibilities for reachable nodes. |
391 | effective_visibilities: EffectiveVisibilities, | |
416331ca XL |
392 | /// A set of pairs corresponding to modules, where the first module is |
393 | /// reachable via a macro that's defined in the second module. This cannot | |
394 | /// be represented as reachable because it can't handle the following case: | |
395 | /// | |
396 | /// pub mod n { // Should be `Public` | |
397 | /// pub(crate) mod p { // Should *not* be accessible | |
398 | /// pub fn f() -> i32 { 12 } // Must be `Reachable` | |
399 | /// } | |
400 | /// } | |
401 | /// pub macro m() { | |
402 | /// n::p::f() | |
403 | /// } | |
94222f64 | 404 | macro_reachable: FxHashSet<(LocalDefId, LocalDefId)>, |
2b03887a FG |
405 | /// Previous visibility level; `None` means unreachable. |
406 | prev_level: Option<Level>, | |
416331ca | 407 | /// Has something changed in the level map? |
92a42be0 | 408 | changed: bool, |
85aaf69f SL |
409 | } |
410 | ||
dc9dc135 | 411 | struct ReachEverythingInTheInterfaceVisitor<'a, 'tcx> { |
2b03887a | 412 | level: Option<Level>, |
94222f64 | 413 | item_def_id: LocalDefId, |
dc9dc135 | 414 | ev: &'a mut EmbargoVisitor<'tcx>, |
7453a54e SL |
415 | } |
416 | ||
a2a8927a | 417 | impl<'tcx> EmbargoVisitor<'tcx> { |
2b03887a FG |
418 | fn get(&self, def_id: LocalDefId) -> Option<Level> { |
419 | self.effective_visibilities.public_at_level(def_id) | |
92a42be0 SL |
420 | } |
421 | ||
2b03887a | 422 | fn update_with_hir_id(&mut self, hir_id: hir::HirId, level: Option<Level>) -> Option<Level> { |
5099ac24 FG |
423 | let def_id = self.tcx.hir().local_def_id(hir_id); |
424 | self.update(def_id, level) | |
425 | } | |
426 | ||
416331ca | 427 | /// Updates node level and returns the updated level. |
2b03887a | 428 | fn update(&mut self, def_id: LocalDefId, level: Option<Level>) -> Option<Level> { |
94222f64 | 429 | let old_level = self.get(def_id); |
2b03887a | 430 | // Visibility levels can only grow. |
92a42be0 | 431 | if level > old_level { |
2b03887a FG |
432 | self.effective_visibilities.set_public_at_level( |
433 | def_id, | |
434 | || ty::Visibility::Restricted(self.tcx.parent_module_from_def_id(def_id)), | |
435 | level.unwrap(), | |
436 | ); | |
92a42be0 SL |
437 | self.changed = true; |
438 | level | |
439 | } else { | |
440 | old_level | |
441 | } | |
85aaf69f | 442 | } |
7453a54e | 443 | |
dc9dc135 XL |
444 | fn reach( |
445 | &mut self, | |
94222f64 | 446 | def_id: LocalDefId, |
2b03887a | 447 | level: Option<Level>, |
dc9dc135 | 448 | ) -> ReachEverythingInTheInterfaceVisitor<'_, 'tcx> { |
476ff2be | 449 | ReachEverythingInTheInterfaceVisitor { |
2b03887a | 450 | level: cmp::min(level, Some(Level::Reachable)), |
94222f64 | 451 | item_def_id: def_id, |
476ff2be SL |
452 | ev: self, |
453 | } | |
7453a54e | 454 | } |
9fa01778 | 455 | |
94222f64 XL |
456 | // We have to make sure that the items that macros might reference |
457 | // are reachable, since they might be exported transitively. | |
458 | fn update_reachability_from_macro(&mut self, local_def_id: LocalDefId, md: &MacroDef) { | |
459 | // Non-opaque macros cannot make other items more accessible than they already are. | |
460 | ||
461 | let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id); | |
462 | let attrs = self.tcx.hir().attrs(hir_id); | |
c295e0f8 | 463 | if attr::find_transparency(attrs, md.macro_rules).0 != Transparency::Opaque { |
94222f64 XL |
464 | return; |
465 | } | |
466 | ||
04454e1e | 467 | let macro_module_def_id = self.tcx.local_parent(local_def_id); |
064997fb | 468 | if self.tcx.opt_def_kind(macro_module_def_id) != Some(DefKind::Mod) { |
94222f64 XL |
469 | // The macro's parent doesn't correspond to a `mod`, return early (#63164, #65252). |
470 | return; | |
471 | } | |
472 | ||
473 | if self.get(local_def_id).is_none() { | |
474 | return; | |
475 | } | |
476 | ||
477 | // Since we are starting from an externally visible module, | |
478 | // all the parents in the loop below are also guaranteed to be modules. | |
479 | let mut module_def_id = macro_module_def_id; | |
480 | loop { | |
481 | let changed_reachability = | |
482 | self.update_macro_reachable(module_def_id, macro_module_def_id); | |
483 | if changed_reachability || module_def_id == CRATE_DEF_ID { | |
484 | break; | |
485 | } | |
04454e1e | 486 | module_def_id = self.tcx.local_parent(module_def_id); |
94222f64 XL |
487 | } |
488 | } | |
489 | ||
416331ca XL |
490 | /// Updates the item as being reachable through a macro defined in the given |
491 | /// module. Returns `true` if the level has changed. | |
94222f64 XL |
492 | fn update_macro_reachable( |
493 | &mut self, | |
494 | module_def_id: LocalDefId, | |
495 | defining_mod: LocalDefId, | |
496 | ) -> bool { | |
497 | if self.macro_reachable.insert((module_def_id, defining_mod)) { | |
498 | self.update_macro_reachable_mod(module_def_id, defining_mod); | |
416331ca XL |
499 | true |
500 | } else { | |
501 | false | |
502 | } | |
503 | } | |
504 | ||
94222f64 | 505 | fn update_macro_reachable_mod(&mut self, module_def_id: LocalDefId, defining_mod: LocalDefId) { |
416331ca | 506 | let module = self.tcx.hir().get_module(module_def_id).0; |
dfeec247 | 507 | for item_id in module.item_ids { |
2b03887a FG |
508 | let def_kind = self.tcx.def_kind(item_id.owner_id); |
509 | let vis = self.tcx.local_visibility(item_id.owner_id.def_id); | |
510 | self.update_macro_reachable_def(item_id.owner_id.def_id, def_kind, vis, defining_mod); | |
416331ca | 511 | } |
5099ac24 | 512 | if let Some(exports) = self.tcx.module_reexports(module_def_id) { |
416331ca | 513 | for export in exports { |
f2b60f7d | 514 | if export.vis.is_accessible_from(defining_mod, self.tcx) { |
416331ca | 515 | if let Res::Def(def_kind, def_id) = export.res { |
f9f354fc | 516 | if let Some(def_id) = def_id.as_local() { |
f2b60f7d | 517 | let vis = self.tcx.local_visibility(def_id); |
94222f64 | 518 | self.update_macro_reachable_def(def_id, def_kind, vis, defining_mod); |
416331ca XL |
519 | } |
520 | } | |
521 | } | |
522 | } | |
523 | } | |
524 | } | |
525 | ||
526 | fn update_macro_reachable_def( | |
527 | &mut self, | |
94222f64 | 528 | def_id: LocalDefId, |
416331ca XL |
529 | def_kind: DefKind, |
530 | vis: ty::Visibility, | |
94222f64 | 531 | module: LocalDefId, |
416331ca | 532 | ) { |
2b03887a | 533 | let level = Some(Level::Reachable); |
3c0e092e | 534 | if vis.is_public() { |
94222f64 | 535 | self.update(def_id, level); |
416331ca XL |
536 | } |
537 | match def_kind { | |
538 | // No type privacy, so can be directly marked as reachable. | |
5e7ed085 | 539 | DefKind::Const | DefKind::Static(_) | DefKind::TraitAlias | DefKind::TyAlias => { |
f2b60f7d | 540 | if vis.is_accessible_from(module, self.tcx) { |
94222f64 XL |
541 | self.update(def_id, level); |
542 | } | |
543 | } | |
544 | ||
5e7ed085 | 545 | // Hygiene isn't really implemented for `macro_rules!` macros at the |
94222f64 | 546 | // moment. Accordingly, marking them as reachable is unwise. `macro` macros |
5e7ed085 | 547 | // have normal hygiene, so we can treat them like other items without type |
94222f64 XL |
548 | // privacy and mark them reachable. |
549 | DefKind::Macro(_) => { | |
a2a8927a | 550 | let item = self.tcx.hir().expect_item(def_id); |
5e7ed085 | 551 | if let hir::ItemKind::Macro(MacroDef { macro_rules: false, .. }, _) = item.kind { |
f2b60f7d | 552 | if vis.is_accessible_from(module, self.tcx) { |
94222f64 XL |
553 | self.update(def_id, level); |
554 | } | |
416331ca | 555 | } |
dfeec247 | 556 | } |
416331ca XL |
557 | |
558 | // We can't use a module name as the final segment of a path, except | |
559 | // in use statements. Since re-export checking doesn't consider | |
560 | // hygiene these don't need to be marked reachable. The contents of | |
561 | // the module, however may be reachable. | |
562 | DefKind::Mod => { | |
f2b60f7d | 563 | if vis.is_accessible_from(module, self.tcx) { |
94222f64 | 564 | self.update_macro_reachable(def_id, module); |
416331ca XL |
565 | } |
566 | } | |
567 | ||
568 | DefKind::Struct | DefKind::Union => { | |
94222f64 | 569 | // While structs and unions have type privacy, their fields do not. |
3c0e092e | 570 | if vis.is_public() { |
a2a8927a | 571 | let item = self.tcx.hir().expect_item(def_id); |
416331ca | 572 | if let hir::ItemKind::Struct(ref struct_def, _) |
dfeec247 | 573 | | hir::ItemKind::Union(ref struct_def, _) = item.kind |
416331ca XL |
574 | { |
575 | for field in struct_def.fields() { | |
94222f64 | 576 | let def_id = self.tcx.hir().local_def_id(field.hir_id); |
f2b60f7d FG |
577 | let field_vis = self.tcx.local_visibility(def_id); |
578 | if field_vis.is_accessible_from(module, self.tcx) { | |
94222f64 | 579 | self.reach(def_id, level).ty(); |
416331ca XL |
580 | } |
581 | } | |
582 | } else { | |
583 | bug!("item {:?} with DefKind {:?}", item, def_kind); | |
584 | } | |
585 | } | |
586 | } | |
587 | ||
588 | // These have type privacy, so are not reachable unless they're | |
f9f354fc | 589 | // public, or are not namespaced at all. |
416331ca XL |
590 | DefKind::AssocConst |
591 | | DefKind::AssocTy | |
416331ca XL |
592 | | DefKind::ConstParam |
593 | | DefKind::Ctor(_, _) | |
594 | | DefKind::Enum | |
595 | | DefKind::ForeignTy | |
596 | | DefKind::Fn | |
597 | | DefKind::OpaqueTy | |
f2b60f7d | 598 | | DefKind::ImplTraitPlaceholder |
ba9703b0 | 599 | | DefKind::AssocFn |
416331ca XL |
600 | | DefKind::Trait |
601 | | DefKind::TyParam | |
f9f354fc XL |
602 | | DefKind::Variant |
603 | | DefKind::LifetimeParam | |
604 | | DefKind::ExternCrate | |
605 | | DefKind::Use | |
606 | | DefKind::ForeignMod | |
607 | | DefKind::AnonConst | |
3c0e092e | 608 | | DefKind::InlineConst |
f9f354fc XL |
609 | | DefKind::Field |
610 | | DefKind::GlobalAsm | |
611 | | DefKind::Impl | |
612 | | DefKind::Closure | |
613 | | DefKind::Generator => (), | |
416331ca XL |
614 | } |
615 | } | |
85aaf69f SL |
616 | } |
617 | ||
a2a8927a | 618 | impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { |
5099ac24 | 619 | type NestedFilter = nested_filter::All; |
dfeec247 | 620 | |
92a42be0 SL |
621 | /// We want to visit items in the context of their containing |
622 | /// module and so forth, so supply a crate for doing a deep walk. | |
5099ac24 FG |
623 | fn nested_visit_map(&mut self) -> Self::Map { |
624 | self.tcx.hir() | |
92a42be0 | 625 | } |
85aaf69f | 626 | |
dfeec247 | 627 | fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { |
5099ac24 | 628 | let item_level = match item.kind { |
dfeec247 | 629 | hir::ItemKind::Impl { .. } => { |
2b03887a FG |
630 | let impl_level = Option::<Level>::of_impl( |
631 | item.owner_id.def_id, | |
632 | self.tcx, | |
633 | &self.effective_visibilities, | |
634 | ); | |
635 | self.update(item.owner_id.def_id, impl_level) | |
85aaf69f | 636 | } |
2b03887a | 637 | _ => self.get(item.owner_id.def_id), |
92a42be0 | 638 | }; |
85aaf69f | 639 | |
0731742a | 640 | // Update levels of nested things. |
e74abb32 | 641 | match item.kind { |
8faf50e0 | 642 | hir::ItemKind::Enum(ref def, _) => { |
dfeec247 | 643 | for variant in def.variants { |
5099ac24 | 644 | let variant_level = self.update_with_hir_id(variant.id, item_level); |
e1599b0c | 645 | if let Some(ctor_hir_id) = variant.data.ctor_hir_id() { |
5099ac24 | 646 | self.update_with_hir_id(ctor_hir_id, item_level); |
532ac7d7 | 647 | } |
e1599b0c | 648 | for field in variant.data.fields() { |
5099ac24 | 649 | self.update_with_hir_id(field.hir_id, variant_level); |
92a42be0 | 650 | } |
85aaf69f SL |
651 | } |
652 | } | |
5869c6ff XL |
653 | hir::ItemKind::Impl(ref impl_) => { |
654 | for impl_item_ref in impl_.items { | |
c295e0f8 | 655 | if impl_.of_trait.is_some() |
2b03887a | 656 | || self.tcx.visibility(impl_item_ref.id.owner_id).is_public() |
c295e0f8 | 657 | { |
2b03887a | 658 | self.update(impl_item_ref.id.owner_id.def_id, item_level); |
85aaf69f SL |
659 | } |
660 | } | |
661 | } | |
dfeec247 | 662 | hir::ItemKind::Trait(.., trait_item_refs) => { |
32a655c1 | 663 | for trait_item_ref in trait_item_refs { |
2b03887a | 664 | self.update(trait_item_ref.id.owner_id.def_id, item_level); |
85aaf69f SL |
665 | } |
666 | } | |
8faf50e0 | 667 | hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => { |
532ac7d7 | 668 | if let Some(ctor_hir_id) = def.ctor_hir_id() { |
5099ac24 | 669 | self.update_with_hir_id(ctor_hir_id, item_level); |
85aaf69f | 670 | } |
b039eaaf | 671 | for field in def.fields() { |
04454e1e FG |
672 | let def_id = self.tcx.hir().local_def_id(field.hir_id); |
673 | let vis = self.tcx.visibility(def_id); | |
674 | if vis.is_public() { | |
5099ac24 | 675 | self.update_with_hir_id(field.hir_id, item_level); |
c34b1796 AL |
676 | } |
677 | } | |
85aaf69f | 678 | } |
5e7ed085 | 679 | hir::ItemKind::Macro(ref macro_def, _) => { |
2b03887a | 680 | self.update_reachability_from_macro(item.owner_id.def_id, macro_def); |
94222f64 | 681 | } |
fc512014 XL |
682 | hir::ItemKind::ForeignMod { items, .. } => { |
683 | for foreign_item in items { | |
2b03887a FG |
684 | if self.tcx.visibility(foreign_item.id.owner_id).is_public() { |
685 | self.update(foreign_item.id.owner_id.def_id, item_level); | |
92a42be0 SL |
686 | } |
687 | } | |
688 | } | |
94222f64 | 689 | |
dfeec247 XL |
690 | hir::ItemKind::OpaqueTy(..) |
691 | | hir::ItemKind::Use(..) | |
692 | | hir::ItemKind::Static(..) | |
693 | | hir::ItemKind::Const(..) | |
694 | | hir::ItemKind::GlobalAsm(..) | |
695 | | hir::ItemKind::TyAlias(..) | |
696 | | hir::ItemKind::Mod(..) | |
697 | | hir::ItemKind::TraitAlias(..) | |
698 | | hir::ItemKind::Fn(..) | |
699 | | hir::ItemKind::ExternCrate(..) => {} | |
7453a54e SL |
700 | } |
701 | ||
0731742a | 702 | // Mark all items in interfaces of reachable items as reachable. |
e74abb32 | 703 | match item.kind { |
0731742a | 704 | // The interface is empty. |
94222f64 | 705 | hir::ItemKind::Macro(..) | hir::ItemKind::ExternCrate(..) => {} |
0731742a | 706 | // All nested items are checked by `visit_item`. |
8faf50e0 | 707 | hir::ItemKind::Mod(..) => {} |
2b03887a | 708 | // Handled in `rustc_resolve`. |
5099ac24 | 709 | hir::ItemKind::Use(..) => {} |
0731742a | 710 | // The interface is empty. |
8faf50e0 | 711 | hir::ItemKind::GlobalAsm(..) => {} |
f2b60f7d | 712 | hir::ItemKind::OpaqueTy(ref opaque) => { |
3dfed10e | 713 | // HACK(jynelson): trying to infer the type of `impl trait` breaks `async-std` (and `pub async fn` in general) |
fc512014 | 714 | // Since rustdoc never needs to do codegen and doesn't care about link-time reachability, |
3dfed10e XL |
715 | // mark this as unreachable. |
716 | // See https://github.com/rust-lang/rust/issues/75100 | |
f2b60f7d | 717 | if !opaque.in_trait && !self.tcx.sess.opts.actually_rustdoc { |
3dfed10e XL |
718 | // FIXME: This is some serious pessimization intended to workaround deficiencies |
719 | // in the reachability pass (`middle/reachable.rs`). Types are marked as link-time | |
720 | // reachable if they are returned via `impl Trait`, even from private functions. | |
2b03887a FG |
721 | let exist_level = cmp::max(item_level, Some(Level::ReachableThroughImplTrait)); |
722 | self.reach(item.owner_id.def_id, exist_level).generics().predicates().ty(); | |
3dfed10e | 723 | } |
0731742a XL |
724 | } |
725 | // Visit everything. | |
dfeec247 XL |
726 | hir::ItemKind::Const(..) |
727 | | hir::ItemKind::Static(..) | |
728 | | hir::ItemKind::Fn(..) | |
729 | | hir::ItemKind::TyAlias(..) => { | |
7453a54e | 730 | if item_level.is_some() { |
2b03887a | 731 | self.reach(item.owner_id.def_id, item_level).generics().predicates().ty(); |
7453a54e SL |
732 | } |
733 | } | |
dfeec247 | 734 | hir::ItemKind::Trait(.., trait_item_refs) => { |
476ff2be | 735 | if item_level.is_some() { |
2b03887a | 736 | self.reach(item.owner_id.def_id, item_level).generics().predicates(); |
476ff2be | 737 | |
32a655c1 | 738 | for trait_item_ref in trait_item_refs { |
064997fb | 739 | let tcx = self.tcx; |
2b03887a | 740 | let mut reach = self.reach(trait_item_ref.id.owner_id.def_id, item_level); |
476ff2be SL |
741 | reach.generics().predicates(); |
742 | ||
dfeec247 | 743 | if trait_item_ref.kind == AssocItemKind::Type |
2b03887a | 744 | && !tcx.impl_defaultness(trait_item_ref.id.owner_id).has_value() |
dfeec247 | 745 | { |
476ff2be SL |
746 | // No type to visit. |
747 | } else { | |
7cac9316 | 748 | reach.ty(); |
476ff2be SL |
749 | } |
750 | } | |
751 | } | |
752 | } | |
8faf50e0 | 753 | hir::ItemKind::TraitAlias(..) => { |
ff7c6d11 | 754 | if item_level.is_some() { |
2b03887a | 755 | self.reach(item.owner_id.def_id, item_level).generics().predicates(); |
ff7c6d11 XL |
756 | } |
757 | } | |
0731742a | 758 | // Visit everything except for private impl items. |
5869c6ff | 759 | hir::ItemKind::Impl(ref impl_) => { |
476ff2be | 760 | if item_level.is_some() { |
2b03887a FG |
761 | self.reach(item.owner_id.def_id, item_level) |
762 | .generics() | |
763 | .predicates() | |
764 | .ty() | |
765 | .trait_ref(); | |
476ff2be | 766 | |
5869c6ff | 767 | for impl_item_ref in impl_.items { |
2b03887a | 768 | let impl_item_level = self.get(impl_item_ref.id.owner_id.def_id); |
0731742a | 769 | if impl_item_level.is_some() { |
2b03887a | 770 | self.reach(impl_item_ref.id.owner_id.def_id, impl_item_level) |
dfeec247 XL |
771 | .generics() |
772 | .predicates() | |
773 | .ty(); | |
476ff2be SL |
774 | } |
775 | } | |
776 | } | |
777 | } | |
778 | ||
0731742a | 779 | // Visit everything, but enum variants have their own levels. |
8faf50e0 | 780 | hir::ItemKind::Enum(ref def, _) => { |
7453a54e | 781 | if item_level.is_some() { |
2b03887a | 782 | self.reach(item.owner_id.def_id, item_level).generics().predicates(); |
7453a54e | 783 | } |
dfeec247 | 784 | for variant in def.variants { |
94222f64 | 785 | let variant_level = self.get(self.tcx.hir().local_def_id(variant.id)); |
0731742a | 786 | if variant_level.is_some() { |
e1599b0c | 787 | for field in variant.data.fields() { |
94222f64 XL |
788 | self.reach(self.tcx.hir().local_def_id(field.hir_id), variant_level) |
789 | .ty(); | |
7453a54e SL |
790 | } |
791 | // Corner case: if the variant is reachable, but its | |
792 | // enum is not, make the enum reachable as well. | |
2b03887a | 793 | self.reach(item.owner_id.def_id, variant_level).ty(); |
923072b8 FG |
794 | } |
795 | if let Some(hir_id) = variant.data.ctor_hir_id() { | |
796 | let ctor_def_id = self.tcx.hir().local_def_id(hir_id); | |
797 | let ctor_level = self.get(ctor_def_id); | |
798 | if ctor_level.is_some() { | |
2b03887a | 799 | self.reach(item.owner_id.def_id, ctor_level).ty(); |
923072b8 | 800 | } |
7453a54e SL |
801 | } |
802 | } | |
803 | } | |
0731742a | 804 | // Visit everything, but foreign items have their own levels. |
fc512014 XL |
805 | hir::ItemKind::ForeignMod { items, .. } => { |
806 | for foreign_item in items { | |
2b03887a | 807 | let foreign_item_level = self.get(foreign_item.id.owner_id.def_id); |
0731742a | 808 | if foreign_item_level.is_some() { |
2b03887a | 809 | self.reach(foreign_item.id.owner_id.def_id, foreign_item_level) |
dfeec247 XL |
810 | .generics() |
811 | .predicates() | |
812 | .ty(); | |
7453a54e SL |
813 | } |
814 | } | |
815 | } | |
0731742a | 816 | // Visit everything except for private fields. |
dfeec247 | 817 | hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => { |
7453a54e | 818 | if item_level.is_some() { |
2b03887a | 819 | self.reach(item.owner_id.def_id, item_level).generics().predicates(); |
7453a54e | 820 | for field in struct_def.fields() { |
94222f64 XL |
821 | let def_id = self.tcx.hir().local_def_id(field.hir_id); |
822 | let field_level = self.get(def_id); | |
0731742a | 823 | if field_level.is_some() { |
94222f64 | 824 | self.reach(def_id, field_level).ty(); |
85aaf69f SL |
825 | } |
826 | } | |
827 | } | |
923072b8 FG |
828 | if let Some(hir_id) = struct_def.ctor_hir_id() { |
829 | let ctor_def_id = self.tcx.hir().local_def_id(hir_id); | |
830 | let ctor_level = self.get(ctor_def_id); | |
831 | if ctor_level.is_some() { | |
2b03887a | 832 | self.reach(item.owner_id.def_id, ctor_level).ty(); |
923072b8 FG |
833 | } |
834 | } | |
85aaf69f | 835 | } |
85aaf69f SL |
836 | } |
837 | ||
0731742a | 838 | let orig_level = mem::replace(&mut self.prev_level, item_level); |
92a42be0 | 839 | intravisit::walk_item(self, item); |
92a42be0 | 840 | self.prev_level = orig_level; |
85aaf69f SL |
841 | } |
842 | ||
dfeec247 | 843 | fn visit_block(&mut self, b: &'tcx hir::Block<'tcx>) { |
92a42be0 SL |
844 | // Blocks can have public items, for example impls, but they always |
845 | // start as completely private regardless of publicity of a function, | |
0731742a XL |
846 | // constant, type, field, etc., in which this block resides. |
847 | let orig_level = mem::replace(&mut self.prev_level, None); | |
92a42be0 | 848 | intravisit::walk_block(self, b); |
92a42be0 | 849 | self.prev_level = orig_level; |
85aaf69f | 850 | } |
7453a54e SL |
851 | } |
852 | ||
a2a8927a | 853 | impl ReachEverythingInTheInterfaceVisitor<'_, '_> { |
476ff2be | 854 | fn generics(&mut self) -> &mut Self { |
94b46f34 XL |
855 | for param in &self.ev.tcx.generics_of(self.item_def_id).params { |
856 | match param.kind { | |
532ac7d7 | 857 | GenericParamDefKind::Lifetime => {} |
94b46f34 XL |
858 | GenericParamDefKind::Type { has_default, .. } => { |
859 | if has_default { | |
0731742a | 860 | self.visit(self.ev.tcx.type_of(param.def_id)); |
94b46f34 XL |
861 | } |
862 | } | |
5e7ed085 | 863 | GenericParamDefKind::Const { has_default } => { |
532ac7d7 | 864 | self.visit(self.ev.tcx.type_of(param.def_id)); |
cdc7bbd5 XL |
865 | if has_default { |
866 | self.visit(self.ev.tcx.const_param_default(param.def_id)); | |
867 | } | |
532ac7d7 | 868 | } |
8bb4bdeb XL |
869 | } |
870 | } | |
476ff2be SL |
871 | self |
872 | } | |
9e0c209e | 873 | |
476ff2be | 874 | fn predicates(&mut self) -> &mut Self { |
0731742a | 875 | self.visit_predicates(self.ev.tcx.predicates_of(self.item_def_id)); |
476ff2be SL |
876 | self |
877 | } | |
878 | ||
7cac9316 | 879 | fn ty(&mut self) -> &mut Self { |
0731742a | 880 | self.visit(self.ev.tcx.type_of(self.item_def_id)); |
476ff2be SL |
881 | self |
882 | } | |
883 | ||
0731742a XL |
884 | fn trait_ref(&mut self) -> &mut Self { |
885 | if let Some(trait_ref) = self.ev.tcx.impl_trait_ref(self.item_def_id) { | |
886 | self.visit_trait(trait_ref); | |
041b39d2 | 887 | } |
476ff2be SL |
888 | self |
889 | } | |
890 | } | |
891 | ||
a2a8927a | 892 | impl<'tcx> DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> { |
dfeec247 XL |
893 | fn tcx(&self) -> TyCtxt<'tcx> { |
894 | self.ev.tcx | |
895 | } | |
29967ef6 XL |
896 | fn visit_def_id( |
897 | &mut self, | |
898 | def_id: DefId, | |
899 | _kind: &str, | |
900 | _descr: &dyn fmt::Display, | |
fc512014 | 901 | ) -> ControlFlow<Self::BreakTy> { |
f9f354fc | 902 | if let Some(def_id) = def_id.as_local() { |
2b03887a FG |
903 | if let (ty::Visibility::Public, _) | (_, Some(Level::ReachableThroughImplTrait)) = |
904 | (self.tcx().visibility(def_id.to_def_id()), self.level) | |
416331ca | 905 | { |
2b03887a | 906 | self.ev.update(def_id, self.level); |
416331ca | 907 | } |
7453a54e | 908 | } |
29967ef6 | 909 | ControlFlow::CONTINUE |
7453a54e | 910 | } |
7453a54e SL |
911 | } |
912 | ||
f2b60f7d | 913 | //////////////////////////////////////////////////////////////////////////////// |
2b03887a | 914 | /// Visitor, used for EffectiveVisibilities table checking |
f2b60f7d FG |
915 | //////////////////////////////////////////////////////////////////////////////// |
916 | pub struct TestReachabilityVisitor<'tcx, 'a> { | |
917 | tcx: TyCtxt<'tcx>, | |
2b03887a | 918 | effective_visibilities: &'a EffectiveVisibilities, |
f2b60f7d FG |
919 | } |
920 | ||
921 | impl<'tcx, 'a> TestReachabilityVisitor<'tcx, 'a> { | |
2b03887a FG |
922 | fn effective_visibility_diagnostic(&mut self, def_id: LocalDefId) { |
923 | if self.tcx.has_attr(def_id.to_def_id(), sym::rustc_effective_visibility) { | |
924 | let mut error_msg = String::new(); | |
f2b60f7d | 925 | let span = self.tcx.def_span(def_id.to_def_id()); |
2b03887a FG |
926 | if let Some(effective_vis) = self.effective_visibilities.effective_vis(def_id) { |
927 | for level in Level::all_levels() { | |
928 | let vis_str = match effective_vis.at_level(level) { | |
929 | ty::Visibility::Restricted(restricted_id) => { | |
930 | if restricted_id.is_top_level_module() { | |
931 | "pub(crate)".to_string() | |
932 | } else if *restricted_id == self.tcx.parent_module_from_def_id(def_id) { | |
933 | "pub(self)".to_string() | |
934 | } else { | |
935 | format!("pub({})", self.tcx.item_name(restricted_id.to_def_id())) | |
936 | } | |
937 | } | |
938 | ty::Visibility::Public => "pub".to_string(), | |
939 | }; | |
940 | if level != Level::Direct { | |
941 | error_msg.push_str(", "); | |
942 | } | |
943 | error_msg.push_str(&format!("{:?}: {}", level, vis_str)); | |
944 | } | |
945 | } else { | |
946 | error_msg.push_str("not in the table"); | |
947 | } | |
948 | self.tcx.sess.emit_err(ReportEffectiveVisibility { span, descr: error_msg }); | |
f2b60f7d FG |
949 | } |
950 | } | |
951 | } | |
952 | ||
953 | impl<'tcx, 'a> Visitor<'tcx> for TestReachabilityVisitor<'tcx, 'a> { | |
954 | fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { | |
2b03887a | 955 | self.effective_visibility_diagnostic(item.owner_id.def_id); |
f2b60f7d FG |
956 | |
957 | match item.kind { | |
958 | hir::ItemKind::Enum(ref def, _) => { | |
959 | for variant in def.variants.iter() { | |
960 | let variant_id = self.tcx.hir().local_def_id(variant.id); | |
2b03887a | 961 | self.effective_visibility_diagnostic(variant_id); |
f2b60f7d FG |
962 | for field in variant.data.fields() { |
963 | let def_id = self.tcx.hir().local_def_id(field.hir_id); | |
2b03887a | 964 | self.effective_visibility_diagnostic(def_id); |
f2b60f7d FG |
965 | } |
966 | } | |
967 | } | |
968 | hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => { | |
969 | for field in def.fields() { | |
970 | let def_id = self.tcx.hir().local_def_id(field.hir_id); | |
2b03887a | 971 | self.effective_visibility_diagnostic(def_id); |
f2b60f7d FG |
972 | } |
973 | } | |
974 | _ => {} | |
975 | } | |
976 | } | |
977 | ||
978 | fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem<'tcx>) { | |
2b03887a | 979 | self.effective_visibility_diagnostic(item.owner_id.def_id); |
f2b60f7d FG |
980 | } |
981 | fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem<'tcx>) { | |
2b03887a | 982 | self.effective_visibility_diagnostic(item.owner_id.def_id); |
f2b60f7d FG |
983 | } |
984 | fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { | |
2b03887a | 985 | self.effective_visibility_diagnostic(item.owner_id.def_id); |
f2b60f7d FG |
986 | } |
987 | } | |
988 | ||
7cac9316 XL |
989 | ////////////////////////////////////////////////////////////////////////////////////// |
990 | /// Name privacy visitor, checks privacy and reports violations. | |
991 | /// Most of name privacy checks are performed during the main resolution phase, | |
992 | /// or later in type checking when field accesses and associated items are resolved. | |
993 | /// This pass performs remaining checks for fields in struct expressions and patterns. | |
994 | ////////////////////////////////////////////////////////////////////////////////////// | |
85aaf69f | 995 | |
f035d41b | 996 | struct NamePrivacyVisitor<'tcx> { |
dc9dc135 | 997 | tcx: TyCtxt<'tcx>, |
3dfed10e | 998 | maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>, |
94222f64 | 999 | current_item: LocalDefId, |
85aaf69f SL |
1000 | } |
1001 | ||
f035d41b | 1002 | impl<'tcx> NamePrivacyVisitor<'tcx> { |
3dfed10e | 1003 | /// Gets the type-checking results for the current body. |
f035d41b XL |
1004 | /// As this will ICE if called outside bodies, only call when working with |
1005 | /// `Expr` or `Pat` nodes (they are guaranteed to be found only in bodies). | |
1006 | #[track_caller] | |
3dfed10e XL |
1007 | fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> { |
1008 | self.maybe_typeck_results | |
1009 | .expect("`NamePrivacyVisitor::typeck_results` called outside of body") | |
f035d41b XL |
1010 | } |
1011 | ||
0531ce1d | 1012 | // Checks that a field in a struct constructor (expression or pattern) is accessible. |
dfeec247 XL |
1013 | fn check_field( |
1014 | &mut self, | |
1015 | use_ctxt: Span, // syntax context of the field name at the use site | |
1016 | span: Span, // span of the field pattern, e.g., `x: 0` | |
5e7ed085 | 1017 | def: ty::AdtDef<'tcx>, // definition of the struct or enum |
dfeec247 | 1018 | field: &'tcx ty::FieldDef, |
ba9703b0 | 1019 | in_update_syntax: bool, |
dfeec247 | 1020 | ) { |
94222f64 XL |
1021 | if def.is_enum() { |
1022 | return; | |
1023 | } | |
1024 | ||
dfeec247 | 1025 | // definition of the field |
5869c6ff | 1026 | let ident = Ident::new(kw::Empty, use_ctxt); |
94222f64 | 1027 | let hir_id = self.tcx.hir().local_def_id_to_hir_id(self.current_item); |
5e7ed085 | 1028 | let def_id = self.tcx.adjust_ident_and_get_scope(ident, def.did(), hir_id).1; |
94222f64 | 1029 | if !field.vis.is_accessible_from(def_id, self.tcx) { |
064997fb | 1030 | self.tcx.sess.emit_err(FieldIsPrivate { |
dfeec247 | 1031 | span, |
064997fb FG |
1032 | field_name: field.name, |
1033 | variant_descr: def.variant_descr(), | |
1034 | def_path_str: self.tcx.def_path_str(def.did()), | |
1035 | label: if in_update_syntax { | |
1036 | FieldIsPrivateLabel::IsUpdateSyntax { span, field_name: field.name } | |
1037 | } else { | |
1038 | FieldIsPrivateLabel::Other { span } | |
1039 | }, | |
1040 | }); | |
85aaf69f SL |
1041 | } |
1042 | } | |
85aaf69f SL |
1043 | } |
1044 | ||
f035d41b | 1045 | impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> { |
5099ac24 | 1046 | type NestedFilter = nested_filter::All; |
dfeec247 | 1047 | |
92a42be0 SL |
1048 | /// We want to visit items in the context of their containing |
1049 | /// module and so forth, so supply a crate for doing a deep walk. | |
5099ac24 FG |
1050 | fn nested_visit_map(&mut self) -> Self::Map { |
1051 | self.tcx.hir() | |
32a655c1 SL |
1052 | } |
1053 | ||
dfeec247 | 1054 | fn visit_mod(&mut self, _m: &'tcx hir::Mod<'tcx>, _s: Span, _n: hir::HirId) { |
9fa01778 | 1055 | // Don't visit nested modules, since we run a separate visitor walk |
2b03887a | 1056 | // for each module in `effective_visibilities` |
9fa01778 XL |
1057 | } |
1058 | ||
32a655c1 | 1059 | fn visit_nested_body(&mut self, body: hir::BodyId) { |
3dfed10e XL |
1060 | let old_maybe_typeck_results = |
1061 | self.maybe_typeck_results.replace(self.tcx.typeck_body(body)); | |
0731742a | 1062 | let body = self.tcx.hir().body(body); |
32a655c1 | 1063 | self.visit_body(body); |
3dfed10e | 1064 | self.maybe_typeck_results = old_maybe_typeck_results; |
92a42be0 SL |
1065 | } |
1066 | ||
dfeec247 | 1067 | fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { |
2b03887a | 1068 | let orig_current_item = mem::replace(&mut self.current_item, item.owner_id.def_id); |
92a42be0 | 1069 | intravisit::walk_item(self, item); |
7cac9316 | 1070 | self.current_item = orig_current_item; |
85aaf69f SL |
1071 | } |
1072 | ||
dfeec247 | 1073 | fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { |
c295e0f8 | 1074 | if let hir::ExprKind::Struct(qpath, fields, ref base) = expr.kind { |
3dfed10e XL |
1075 | let res = self.typeck_results().qpath_res(qpath, expr.hir_id); |
1076 | let adt = self.typeck_results().expr_ty(expr).ty_adt_def().unwrap(); | |
ba9703b0 | 1077 | let variant = adt.variant_of_res(res); |
c295e0f8 | 1078 | if let Some(base) = *base { |
ba9703b0 XL |
1079 | // If the expression uses FRU we need to make sure all the unmentioned fields |
1080 | // are checked for privacy (RFC 736). Rather than computing the set of | |
1081 | // unmentioned fields, just check them all. | |
1082 | for (vf_index, variant_field) in variant.fields.iter().enumerate() { | |
3dfed10e XL |
1083 | let field = fields.iter().find(|f| { |
1084 | self.tcx.field_index(f.hir_id, self.typeck_results()) == vf_index | |
1085 | }); | |
ba9703b0 XL |
1086 | let (use_ctxt, span) = match field { |
1087 | Some(field) => (field.ident.span, field.span), | |
1088 | None => (base.span, base.span), | |
1089 | }; | |
1090 | self.check_field(use_ctxt, span, adt, variant_field, true); | |
1091 | } | |
1092 | } else { | |
1093 | for field in fields { | |
1094 | let use_ctxt = field.ident.span; | |
3dfed10e | 1095 | let index = self.tcx.field_index(field.hir_id, self.typeck_results()); |
ba9703b0 | 1096 | self.check_field(use_ctxt, field.span, adt, &variant.fields[index], false); |
85aaf69f SL |
1097 | } |
1098 | } | |
85aaf69f SL |
1099 | } |
1100 | ||
92a42be0 | 1101 | intravisit::walk_expr(self, expr); |
85aaf69f SL |
1102 | } |
1103 | ||
dfeec247 | 1104 | fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) { |
ba9703b0 | 1105 | if let PatKind::Struct(ref qpath, fields, _) = pat.kind { |
3dfed10e XL |
1106 | let res = self.typeck_results().qpath_res(qpath, pat.hir_id); |
1107 | let adt = self.typeck_results().pat_ty(pat).ty_adt_def().unwrap(); | |
ba9703b0 XL |
1108 | let variant = adt.variant_of_res(res); |
1109 | for field in fields { | |
1110 | let use_ctxt = field.ident.span; | |
3dfed10e | 1111 | let index = self.tcx.field_index(field.hir_id, self.typeck_results()); |
ba9703b0 | 1112 | self.check_field(use_ctxt, field.span, adt, &variant.fields[index], false); |
85aaf69f | 1113 | } |
85aaf69f SL |
1114 | } |
1115 | ||
7cac9316 | 1116 | intravisit::walk_pat(self, pat); |
85aaf69f | 1117 | } |
85aaf69f SL |
1118 | } |
1119 | ||
041b39d2 XL |
1120 | //////////////////////////////////////////////////////////////////////////////////////////// |
1121 | /// Type privacy visitor, checks types for privacy and reports violations. | |
cdc7bbd5 | 1122 | /// Both explicitly written types and inferred types of expressions and patterns are checked. |
041b39d2 XL |
1123 | /// Checks are performed on "semantic" types regardless of names and their hygiene. |
1124 | //////////////////////////////////////////////////////////////////////////////////////////// | |
1125 | ||
f035d41b | 1126 | struct TypePrivacyVisitor<'tcx> { |
dc9dc135 | 1127 | tcx: TyCtxt<'tcx>, |
3dfed10e | 1128 | maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>, |
f9f354fc | 1129 | current_item: LocalDefId, |
041b39d2 XL |
1130 | span: Span, |
1131 | } | |
1132 | ||
f035d41b | 1133 | impl<'tcx> TypePrivacyVisitor<'tcx> { |
3dfed10e | 1134 | /// Gets the type-checking results for the current body. |
f035d41b XL |
1135 | /// As this will ICE if called outside bodies, only call when working with |
1136 | /// `Expr` or `Pat` nodes (they are guaranteed to be found only in bodies). | |
1137 | #[track_caller] | |
3dfed10e XL |
1138 | fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> { |
1139 | self.maybe_typeck_results | |
1140 | .expect("`TypePrivacyVisitor::typeck_results` called outside of body") | |
f035d41b XL |
1141 | } |
1142 | ||
041b39d2 | 1143 | fn item_is_accessible(&self, did: DefId) -> bool { |
f2b60f7d | 1144 | self.tcx.visibility(did).is_accessible_from(self.current_item, self.tcx) |
041b39d2 XL |
1145 | } |
1146 | ||
0731742a | 1147 | // Take node-id of an expression or pattern and check its type for privacy. |
3b2f2976 | 1148 | fn check_expr_pat_type(&mut self, id: hir::HirId, span: Span) -> bool { |
041b39d2 | 1149 | self.span = span; |
3dfed10e | 1150 | let typeck_results = self.typeck_results(); |
29967ef6 XL |
1151 | let result: ControlFlow<()> = try { |
1152 | self.visit(typeck_results.node_type(id))?; | |
1153 | self.visit(typeck_results.node_substs(id))?; | |
1154 | if let Some(adjustments) = typeck_results.adjustments().get(id) { | |
1155 | adjustments.iter().try_for_each(|adjustment| self.visit(adjustment.target))?; | |
041b39d2 | 1156 | } |
29967ef6 XL |
1157 | }; |
1158 | result.is_break() | |
041b39d2 | 1159 | } |
ff7c6d11 | 1160 | |
0731742a XL |
1161 | fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool { |
1162 | let is_error = !self.item_is_accessible(def_id); | |
1163 | if is_error { | |
064997fb | 1164 | self.tcx.sess.emit_err(ItemIsPrivate { span: self.span, kind, descr: descr.into() }); |
ff7c6d11 | 1165 | } |
0731742a | 1166 | is_error |
ff7c6d11 | 1167 | } |
041b39d2 XL |
1168 | } |
1169 | ||
f035d41b | 1170 | impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> { |
5099ac24 | 1171 | type NestedFilter = nested_filter::All; |
dfeec247 | 1172 | |
041b39d2 XL |
1173 | /// We want to visit items in the context of their containing |
1174 | /// module and so forth, so supply a crate for doing a deep walk. | |
5099ac24 FG |
1175 | fn nested_visit_map(&mut self) -> Self::Map { |
1176 | self.tcx.hir() | |
041b39d2 XL |
1177 | } |
1178 | ||
dfeec247 | 1179 | fn visit_mod(&mut self, _m: &'tcx hir::Mod<'tcx>, _s: Span, _n: hir::HirId) { |
9fa01778 | 1180 | // Don't visit nested modules, since we run a separate visitor walk |
2b03887a | 1181 | // for each module in `effective_visibilities` |
9fa01778 XL |
1182 | } |
1183 | ||
041b39d2 | 1184 | fn visit_nested_body(&mut self, body: hir::BodyId) { |
3dfed10e XL |
1185 | let old_maybe_typeck_results = |
1186 | self.maybe_typeck_results.replace(self.tcx.typeck_body(body)); | |
0731742a | 1187 | let body = self.tcx.hir().body(body); |
041b39d2 | 1188 | self.visit_body(body); |
3dfed10e | 1189 | self.maybe_typeck_results = old_maybe_typeck_results; |
041b39d2 XL |
1190 | } |
1191 | ||
94222f64 XL |
1192 | fn visit_generic_arg(&mut self, generic_arg: &'tcx hir::GenericArg<'tcx>) { |
1193 | match generic_arg { | |
1194 | hir::GenericArg::Type(t) => self.visit_ty(t), | |
1195 | hir::GenericArg::Infer(inf) => self.visit_infer(inf), | |
1196 | hir::GenericArg::Lifetime(_) | hir::GenericArg::Const(_) => {} | |
1197 | } | |
1198 | } | |
1199 | ||
dfeec247 | 1200 | fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) { |
ea8adc8c | 1201 | self.span = hir_ty.span; |
3dfed10e | 1202 | if let Some(typeck_results) = self.maybe_typeck_results { |
ea8adc8c | 1203 | // Types in bodies. |
29967ef6 | 1204 | if self.visit(typeck_results.node_type(hir_ty.hir_id)).is_break() { |
ea8adc8c XL |
1205 | return; |
1206 | } | |
1207 | } else { | |
1208 | // Types in signatures. | |
1209 | // FIXME: This is very ineffective. Ideally each HIR type should be converted | |
1210 | // into a semantic type only once and the result should be cached somehow. | |
2b03887a | 1211 | if self.visit(rustc_hir_analysis::hir_ty_to_ty(self.tcx, hir_ty)).is_break() { |
ea8adc8c XL |
1212 | return; |
1213 | } | |
1214 | } | |
1215 | ||
1216 | intravisit::walk_ty(self, hir_ty); | |
1217 | } | |
1218 | ||
94222f64 XL |
1219 | fn visit_infer(&mut self, inf: &'tcx hir::InferArg) { |
1220 | self.span = inf.span; | |
1221 | if let Some(typeck_results) = self.maybe_typeck_results { | |
1222 | if let Some(ty) = typeck_results.node_type_opt(inf.hir_id) { | |
1223 | if self.visit(ty).is_break() { | |
1224 | return; | |
1225 | } | |
5099ac24 FG |
1226 | } else { |
1227 | // We don't do anything for const infers here. | |
94222f64 XL |
1228 | } |
1229 | } else { | |
5099ac24 | 1230 | bug!("visit_infer without typeck_results"); |
94222f64 XL |
1231 | } |
1232 | intravisit::walk_inf(self, inf); | |
1233 | } | |
1234 | ||
dfeec247 | 1235 | fn visit_trait_ref(&mut self, trait_ref: &'tcx hir::TraitRef<'tcx>) { |
ff7c6d11 | 1236 | self.span = trait_ref.path.span; |
3dfed10e | 1237 | if self.maybe_typeck_results.is_none() { |
ff7c6d11 XL |
1238 | // Avoid calling `hir_trait_to_predicates` in bodies, it will ICE. |
1239 | // The traits' privacy in bodies is already checked as a part of trait object types. | |
2b03887a | 1240 | let bounds = rustc_hir_analysis::hir_trait_to_predicates( |
ba9703b0 XL |
1241 | self.tcx, |
1242 | trait_ref, | |
1243 | // NOTE: This isn't really right, but the actual type doesn't matter here. It's | |
1244 | // just required by `ty::TraitRef`. | |
1245 | self.tcx.types.never, | |
1246 | ); | |
416331ca | 1247 | |
dfeec247 | 1248 | for (trait_predicate, _, _) in bounds.trait_bounds { |
29967ef6 | 1249 | if self.visit_trait(trait_predicate.skip_binder()).is_break() { |
416331ca XL |
1250 | return; |
1251 | } | |
ff7c6d11 | 1252 | } |
416331ca | 1253 | |
dc9dc135 | 1254 | for (poly_predicate, _) in bounds.projection_bounds { |
5099ac24 FG |
1255 | let pred = poly_predicate.skip_binder(); |
1256 | let poly_pred_term = self.visit(pred.term); | |
1257 | if poly_pred_term.is_break() | |
1258 | || self.visit_projection_ty(pred.projection_ty).is_break() | |
416331ca | 1259 | { |
ff7c6d11 XL |
1260 | return; |
1261 | } | |
1262 | } | |
ea8adc8c XL |
1263 | } |
1264 | ||
1265 | intravisit::walk_trait_ref(self, trait_ref); | |
1266 | } | |
1267 | ||
041b39d2 | 1268 | // Check types of expressions |
dfeec247 | 1269 | fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { |
3b2f2976 | 1270 | if self.check_expr_pat_type(expr.hir_id, expr.span) { |
041b39d2 XL |
1271 | // Do not check nested expressions if the error already happened. |
1272 | return; | |
1273 | } | |
e74abb32 | 1274 | match expr.kind { |
c295e0f8 | 1275 | hir::ExprKind::Assign(_, rhs, _) | hir::ExprKind::Match(rhs, ..) => { |
041b39d2 | 1276 | // Do not report duplicate errors for `x = y` and `match x { ... }`. |
3b2f2976 | 1277 | if self.check_expr_pat_type(rhs.hir_id, rhs.span) { |
041b39d2 XL |
1278 | return; |
1279 | } | |
1280 | } | |
5099ac24 | 1281 | hir::ExprKind::MethodCall(segment, ..) => { |
041b39d2 | 1282 | // Method calls have to be checked specially. |
5099ac24 | 1283 | self.span = segment.ident.span; |
3dfed10e | 1284 | if let Some(def_id) = self.typeck_results().type_dependent_def_id(expr.hir_id) { |
29967ef6 | 1285 | if self.visit(self.tcx.type_of(def_id)).is_break() { |
8faf50e0 XL |
1286 | return; |
1287 | } | |
1288 | } else { | |
dfeec247 XL |
1289 | self.tcx |
1290 | .sess | |
1291 | .delay_span_bug(expr.span, "no type-dependent def for method call"); | |
041b39d2 XL |
1292 | } |
1293 | } | |
1294 | _ => {} | |
1295 | } | |
1296 | ||
1297 | intravisit::walk_expr(self, expr); | |
1298 | } | |
1299 | ||
ff7c6d11 XL |
1300 | // Prohibit access to associated items with insufficient nominal visibility. |
1301 | // | |
1302 | // Additionally, until better reachability analysis for macros 2.0 is available, | |
1303 | // we prohibit access to private statics from other crates, this allows to give | |
1304 | // more code internal visibility at link time. (Access to private functions | |
0531ce1d | 1305 | // is already prohibited by type privacy for function types.) |
dfeec247 | 1306 | fn visit_qpath(&mut self, qpath: &'tcx hir::QPath<'tcx>, id: hir::HirId, span: Span) { |
f035d41b XL |
1307 | let def = match qpath { |
1308 | hir::QPath::Resolved(_, path) => match path.res { | |
1309 | Res::Def(kind, def_id) => Some((kind, def_id)), | |
1310 | _ => None, | |
1311 | }, | |
3dfed10e XL |
1312 | hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self |
1313 | .maybe_typeck_results | |
1314 | .and_then(|typeck_results| typeck_results.type_dependent_def(id)), | |
ff7c6d11 | 1315 | }; |
29967ef6 XL |
1316 | let def = def.filter(|(kind, _)| { |
1317 | matches!( | |
1318 | kind, | |
5e7ed085 | 1319 | DefKind::AssocFn | DefKind::AssocConst | DefKind::AssocTy | DefKind::Static(_) |
29967ef6 | 1320 | ) |
48663c56 XL |
1321 | }); |
1322 | if let Some((kind, def_id)) = def { | |
dfeec247 | 1323 | let is_local_static = |
5e7ed085 | 1324 | if let DefKind::Static(_) = kind { def_id.is_local() } else { false }; |
ff7c6d11 | 1325 | if !self.item_is_accessible(def_id) && !is_local_static { |
ba9703b0 XL |
1326 | let sess = self.tcx.sess; |
1327 | let sm = sess.source_map(); | |
1328 | let name = match qpath { | |
3dfed10e XL |
1329 | hir::QPath::Resolved(..) | hir::QPath::LangItem(..) => { |
1330 | sm.span_to_snippet(qpath.span()).ok() | |
1331 | } | |
ba9703b0 | 1332 | hir::QPath::TypeRelative(_, segment) => Some(segment.ident.to_string()), |
ff7c6d11 | 1333 | }; |
ba9703b0 | 1334 | let kind = kind.descr(def_id); |
064997fb FG |
1335 | let _ = match name { |
1336 | Some(name) => { | |
1337 | sess.emit_err(ItemIsPrivate { span, kind, descr: (&name).into() }) | |
1338 | } | |
1339 | None => sess.emit_err(UnnamedItemIsPrivate { span, kind }), | |
ba9703b0 | 1340 | }; |
ff7c6d11 | 1341 | return; |
041b39d2 XL |
1342 | } |
1343 | } | |
1344 | ||
f2b60f7d | 1345 | intravisit::walk_qpath(self, qpath, id); |
041b39d2 XL |
1346 | } |
1347 | ||
0731742a | 1348 | // Check types of patterns. |
dfeec247 | 1349 | fn visit_pat(&mut self, pattern: &'tcx hir::Pat<'tcx>) { |
3b2f2976 | 1350 | if self.check_expr_pat_type(pattern.hir_id, pattern.span) { |
041b39d2 XL |
1351 | // Do not check nested patterns if the error already happened. |
1352 | return; | |
1353 | } | |
1354 | ||
1355 | intravisit::walk_pat(self, pattern); | |
1356 | } | |
1357 | ||
dfeec247 | 1358 | fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) { |
c295e0f8 | 1359 | if let Some(init) = local.init { |
3b2f2976 | 1360 | if self.check_expr_pat_type(init.hir_id, init.span) { |
041b39d2 XL |
1361 | // Do not report duplicate errors for `let x = y`. |
1362 | return; | |
1363 | } | |
1364 | } | |
1365 | ||
1366 | intravisit::walk_local(self, local); | |
1367 | } | |
1368 | ||
0731742a | 1369 | // Check types in item interfaces. |
dfeec247 | 1370 | fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { |
2b03887a | 1371 | let orig_current_item = mem::replace(&mut self.current_item, item.owner_id.def_id); |
3dfed10e | 1372 | let old_maybe_typeck_results = self.maybe_typeck_results.take(); |
041b39d2 | 1373 | intravisit::walk_item(self, item); |
3dfed10e | 1374 | self.maybe_typeck_results = old_maybe_typeck_results; |
041b39d2 XL |
1375 | self.current_item = orig_current_item; |
1376 | } | |
1377 | } | |
1378 | ||
a2a8927a | 1379 | impl<'tcx> DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> { |
dfeec247 XL |
1380 | fn tcx(&self) -> TyCtxt<'tcx> { |
1381 | self.tcx | |
1382 | } | |
29967ef6 XL |
1383 | fn visit_def_id( |
1384 | &mut self, | |
1385 | def_id: DefId, | |
1386 | kind: &str, | |
1387 | descr: &dyn fmt::Display, | |
fc512014 | 1388 | ) -> ControlFlow<Self::BreakTy> { |
29967ef6 XL |
1389 | if self.check_def_id(def_id, kind, descr) { |
1390 | ControlFlow::BREAK | |
1391 | } else { | |
1392 | ControlFlow::CONTINUE | |
1393 | } | |
041b39d2 XL |
1394 | } |
1395 | } | |
1396 | ||
9cc50fc6 SL |
1397 | /////////////////////////////////////////////////////////////////////////////// |
1398 | /// Obsolete visitors for checking for private items in public interfaces. | |
1399 | /// These visitors are supposed to be kept in frozen state and produce an | |
1400 | /// "old error node set". For backward compatibility the new visitor reports | |
1401 | /// warnings instead of hard errors when the erroneous node is not in this old set. | |
1402 | /////////////////////////////////////////////////////////////////////////////// | |
1403 | ||
dc9dc135 XL |
1404 | struct ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { |
1405 | tcx: TyCtxt<'tcx>, | |
2b03887a | 1406 | effective_visibilities: &'a EffectiveVisibilities, |
85aaf69f | 1407 | in_variant: bool, |
0731742a | 1408 | // Set of errors produced by this obsolete visitor. |
532ac7d7 | 1409 | old_error_set: HirIdSet, |
85aaf69f SL |
1410 | } |
1411 | ||
dc9dc135 | 1412 | struct ObsoleteCheckTypeForPrivatenessVisitor<'a, 'b, 'tcx> { |
9cc50fc6 | 1413 | inner: &'a ObsoleteVisiblePrivateTypesVisitor<'b, 'tcx>, |
0731742a | 1414 | /// Whether the type refers to private types. |
85aaf69f | 1415 | contains_private: bool, |
0731742a XL |
1416 | /// Whether we've recurred at all (i.e., if we're pointing at the |
1417 | /// first type on which `visit_ty` was called). | |
85aaf69f | 1418 | at_outer_type: bool, |
0731742a | 1419 | /// Whether that first type is a public path. |
85aaf69f SL |
1420 | outer_type_is_public_path: bool, |
1421 | } | |
1422 | ||
9cc50fc6 | 1423 | impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { |
dfeec247 | 1424 | fn path_is_private_type(&self, path: &hir::Path<'_>) -> bool { |
48663c56 | 1425 | let did = match path.res { |
2b03887a FG |
1426 | Res::PrimTy(..) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Err => { |
1427 | return false; | |
1428 | } | |
48663c56 | 1429 | res => res.def_id(), |
85aaf69f | 1430 | }; |
b039eaaf | 1431 | |
85aaf69f SL |
1432 | // A path can only be private if: |
1433 | // it's in this crate... | |
f9f354fc | 1434 | if let Some(did) = did.as_local() { |
b039eaaf | 1435 | // .. and it corresponds to a private type in the AST (this returns |
0731742a | 1436 | // `None` for type parameters). |
3dfed10e | 1437 | match self.tcx.hir().find(self.tcx.hir().local_def_id_to_hir_id(did)) { |
04454e1e | 1438 | Some(Node::Item(_)) => !self.tcx.visibility(did).is_public(), |
b039eaaf SL |
1439 | Some(_) | None => false, |
1440 | } | |
1441 | } else { | |
ba9703b0 | 1442 | false |
85aaf69f | 1443 | } |
85aaf69f SL |
1444 | } |
1445 | ||
94222f64 | 1446 | fn trait_is_public(&self, trait_id: LocalDefId) -> bool { |
85aaf69f | 1447 | // FIXME: this would preferably be using `exported_items`, but all |
0731742a | 1448 | // traits are exported currently (see `EmbargoVisitor.exported_trait`). |
2b03887a | 1449 | self.effective_visibilities.is_directly_public(trait_id) |
85aaf69f SL |
1450 | } |
1451 | ||
dfeec247 | 1452 | fn check_generic_bound(&mut self, bound: &hir::GenericBound<'_>) { |
8faf50e0 | 1453 | if let hir::GenericBound::Trait(ref trait_ref, _) = *bound { |
c295e0f8 | 1454 | if self.path_is_private_type(trait_ref.trait_ref.path) { |
532ac7d7 | 1455 | self.old_error_set.insert(trait_ref.trait_ref.hir_ref_id); |
85aaf69f SL |
1456 | } |
1457 | } | |
1458 | } | |
c34b1796 | 1459 | |
04454e1e | 1460 | fn item_is_public(&self, def_id: LocalDefId) -> bool { |
2b03887a | 1461 | self.effective_visibilities.is_reachable(def_id) || self.tcx.visibility(def_id).is_public() |
c34b1796 | 1462 | } |
85aaf69f SL |
1463 | } |
1464 | ||
9cc50fc6 | 1465 | impl<'a, 'b, 'tcx, 'v> Visitor<'v> for ObsoleteCheckTypeForPrivatenessVisitor<'a, 'b, 'tcx> { |
94222f64 XL |
1466 | fn visit_generic_arg(&mut self, generic_arg: &'v hir::GenericArg<'v>) { |
1467 | match generic_arg { | |
1468 | hir::GenericArg::Type(t) => self.visit_ty(t), | |
1469 | hir::GenericArg::Infer(inf) => self.visit_ty(&inf.to_ty()), | |
1470 | hir::GenericArg::Lifetime(_) | hir::GenericArg::Const(_) => {} | |
1471 | } | |
1472 | } | |
1473 | ||
dfeec247 | 1474 | fn visit_ty(&mut self, ty: &hir::Ty<'_>) { |
c295e0f8 | 1475 | if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind { |
476ff2be | 1476 | if self.inner.path_is_private_type(path) { |
85aaf69f | 1477 | self.contains_private = true; |
0731742a | 1478 | // Found what we're looking for, so let's stop working. |
dfeec247 | 1479 | return; |
476ff2be SL |
1480 | } |
1481 | } | |
e74abb32 | 1482 | if let hir::TyKind::Path(_) = ty.kind { |
476ff2be | 1483 | if self.at_outer_type { |
85aaf69f SL |
1484 | self.outer_type_is_public_path = true; |
1485 | } | |
1486 | } | |
1487 | self.at_outer_type = false; | |
92a42be0 | 1488 | intravisit::walk_ty(self, ty) |
85aaf69f SL |
1489 | } |
1490 | ||
0731742a | 1491 | // Don't want to recurse into `[, .. expr]`. |
dfeec247 | 1492 | fn visit_expr(&mut self, _: &hir::Expr<'_>) {} |
85aaf69f SL |
1493 | } |
1494 | ||
476ff2be | 1495 | impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { |
5099ac24 | 1496 | type NestedFilter = nested_filter::All; |
dfeec247 | 1497 | |
92a42be0 SL |
1498 | /// We want to visit items in the context of their containing |
1499 | /// module and so forth, so supply a crate for doing a deep walk. | |
5099ac24 FG |
1500 | fn nested_visit_map(&mut self) -> Self::Map { |
1501 | self.tcx.hir() | |
92a42be0 SL |
1502 | } |
1503 | ||
dfeec247 | 1504 | fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { |
e74abb32 | 1505 | match item.kind { |
0731742a | 1506 | // Contents of a private mod can be re-exported, so we need |
85aaf69f | 1507 | // to check internals. |
8faf50e0 | 1508 | hir::ItemKind::Mod(_) => {} |
85aaf69f SL |
1509 | |
1510 | // An `extern {}` doesn't introduce a new privacy | |
1511 | // namespace (the contents have their own privacies). | |
fc512014 | 1512 | hir::ItemKind::ForeignMod { .. } => {} |
85aaf69f | 1513 | |
c295e0f8 | 1514 | hir::ItemKind::Trait(.., bounds, _) => { |
2b03887a | 1515 | if !self.trait_is_public(item.owner_id.def_id) { |
dfeec247 | 1516 | return; |
85aaf69f SL |
1517 | } |
1518 | ||
62682a34 | 1519 | for bound in bounds.iter() { |
8faf50e0 | 1520 | self.check_generic_bound(bound) |
85aaf69f SL |
1521 | } |
1522 | } | |
1523 | ||
0731742a | 1524 | // Impls need some special handling to try to offer useful |
85aaf69f | 1525 | // error messages without (too many) false positives |
0731742a | 1526 | // (i.e., we could just return here to not check them at |
85aaf69f | 1527 | // all, or some worse estimation of whether an impl is |
c34b1796 | 1528 | // publicly visible). |
5869c6ff | 1529 | hir::ItemKind::Impl(ref impl_) => { |
85aaf69f SL |
1530 | // `impl [... for] Private` is never visible. |
1531 | let self_contains_private; | |
0731742a XL |
1532 | // `impl [... for] Public<...>`, but not `impl [... for] |
1533 | // Vec<Public>` or `(Public,)`, etc. | |
85aaf69f SL |
1534 | let self_is_public_path; |
1535 | ||
0731742a | 1536 | // Check the properties of the `Self` type: |
85aaf69f | 1537 | { |
9cc50fc6 | 1538 | let mut visitor = ObsoleteCheckTypeForPrivatenessVisitor { |
85aaf69f SL |
1539 | inner: self, |
1540 | contains_private: false, | |
1541 | at_outer_type: true, | |
1542 | outer_type_is_public_path: false, | |
1543 | }; | |
c295e0f8 | 1544 | visitor.visit_ty(impl_.self_ty); |
85aaf69f SL |
1545 | self_contains_private = visitor.contains_private; |
1546 | self_is_public_path = visitor.outer_type_is_public_path; | |
1547 | } | |
1548 | ||
0731742a | 1549 | // Miscellaneous info about the impl: |
85aaf69f SL |
1550 | |
1551 | // `true` iff this is `impl Private for ...`. | |
5869c6ff | 1552 | let not_private_trait = impl_.of_trait.as_ref().map_or( |
dfeec247 XL |
1553 | true, // no trait counts as public trait |
1554 | |tr| { | |
94222f64 XL |
1555 | if let Some(def_id) = tr.path.res.def_id().as_local() { |
1556 | self.trait_is_public(def_id) | |
b039eaaf SL |
1557 | } else { |
1558 | true // external traits must be public | |
1559 | } | |
dfeec247 XL |
1560 | }, |
1561 | ); | |
85aaf69f SL |
1562 | |
1563 | // `true` iff this is a trait impl or at least one method is public. | |
1564 | // | |
1565 | // `impl Public { $( fn ...() {} )* }` is not visible. | |
1566 | // | |
1567 | // This is required over just using the methods' privacy | |
1568 | // directly because we might have `impl<T: Foo<Private>> ...`, | |
1569 | // and we shouldn't warn about the generics if all the methods | |
1570 | // are private (because `T` won't be visible externally). | |
5869c6ff XL |
1571 | let trait_or_some_public_method = impl_.of_trait.is_some() |
1572 | || impl_.items.iter().any(|impl_item_ref| { | |
dfeec247 XL |
1573 | let impl_item = self.tcx.hir().impl_item(impl_item_ref.id); |
1574 | match impl_item.kind { | |
2b03887a FG |
1575 | hir::ImplItemKind::Const(..) | hir::ImplItemKind::Fn(..) => self |
1576 | .effective_visibilities | |
1577 | .is_reachable(impl_item_ref.id.owner_id.def_id), | |
1578 | hir::ImplItemKind::Type(_) => false, | |
dfeec247 XL |
1579 | } |
1580 | }); | |
85aaf69f | 1581 | |
dfeec247 | 1582 | if !self_contains_private && not_private_trait && trait_or_some_public_method { |
5869c6ff | 1583 | intravisit::walk_generics(self, &impl_.generics); |
85aaf69f | 1584 | |
5869c6ff | 1585 | match impl_.of_trait { |
85aaf69f | 1586 | None => { |
5869c6ff | 1587 | for impl_item_ref in impl_.items { |
c34b1796 AL |
1588 | // This is where we choose whether to walk down |
1589 | // further into the impl to check its items. We | |
1590 | // should only walk into public items so that we | |
1591 | // don't erroneously report errors for private | |
1592 | // types in private items. | |
0731742a | 1593 | let impl_item = self.tcx.hir().impl_item(impl_item_ref.id); |
e74abb32 | 1594 | match impl_item.kind { |
ba9703b0 | 1595 | hir::ImplItemKind::Const(..) | hir::ImplItemKind::Fn(..) |
2b03887a | 1596 | if self.item_is_public(impl_item.owner_id.def_id) => |
c34b1796 | 1597 | { |
92a42be0 | 1598 | intravisit::walk_impl_item(self, impl_item) |
c34b1796 | 1599 | } |
2b03887a | 1600 | hir::ImplItemKind::Type(..) => { |
92a42be0 | 1601 | intravisit::walk_impl_item(self, impl_item) |
85aaf69f | 1602 | } |
c34b1796 | 1603 | _ => {} |
85aaf69f SL |
1604 | } |
1605 | } | |
1606 | } | |
5869c6ff | 1607 | Some(ref tr) => { |
c34b1796 | 1608 | // Any private types in a trait impl fall into three |
85aaf69f SL |
1609 | // categories. |
1610 | // 1. mentioned in the trait definition | |
1611 | // 2. mentioned in the type params/generics | |
c34b1796 | 1612 | // 3. mentioned in the associated types of the impl |
85aaf69f SL |
1613 | // |
1614 | // Those in 1. can only occur if the trait is in | |
5e7ed085 | 1615 | // this crate and will have been warned about on the |
85aaf69f SL |
1616 | // trait definition (there's no need to warn twice |
1617 | // so we don't check the methods). | |
1618 | // | |
1619 | // Those in 2. are warned via walk_generics and this | |
1620 | // call here. | |
c295e0f8 | 1621 | intravisit::walk_path(self, tr.path); |
c34b1796 AL |
1622 | |
1623 | // Those in 3. are warned with this call. | |
5869c6ff | 1624 | for impl_item_ref in impl_.items { |
0731742a | 1625 | let impl_item = self.tcx.hir().impl_item(impl_item_ref.id); |
2b03887a | 1626 | if let hir::ImplItemKind::Type(ty) = impl_item.kind { |
d9579d0f | 1627 | self.visit_ty(ty); |
c34b1796 AL |
1628 | } |
1629 | } | |
85aaf69f SL |
1630 | } |
1631 | } | |
5869c6ff | 1632 | } else if impl_.of_trait.is_none() && self_is_public_path { |
0731742a | 1633 | // `impl Public<Private> { ... }`. Any public static |
85aaf69f SL |
1634 | // methods will be visible as `Public::foo`. |
1635 | let mut found_pub_static = false; | |
5869c6ff | 1636 | for impl_item_ref in impl_.items { |
2b03887a FG |
1637 | if self |
1638 | .effective_visibilities | |
1639 | .is_reachable(impl_item_ref.id.owner_id.def_id) | |
1640 | || self.tcx.visibility(impl_item_ref.id.owner_id).is_public() | |
c295e0f8 | 1641 | { |
0731742a | 1642 | let impl_item = self.tcx.hir().impl_item(impl_item_ref.id); |
32a655c1 | 1643 | match impl_item_ref.kind { |
dc9dc135 | 1644 | AssocItemKind::Const => { |
d9579d0f | 1645 | found_pub_static = true; |
92a42be0 | 1646 | intravisit::walk_impl_item(self, impl_item); |
d9579d0f | 1647 | } |
ba9703b0 | 1648 | AssocItemKind::Fn { has_self: false } => { |
85aaf69f | 1649 | found_pub_static = true; |
92a42be0 | 1650 | intravisit::walk_impl_item(self, impl_item); |
85aaf69f | 1651 | } |
32a655c1 | 1652 | _ => {} |
85aaf69f | 1653 | } |
85aaf69f SL |
1654 | } |
1655 | } | |
1656 | if found_pub_static { | |
5869c6ff | 1657 | intravisit::walk_generics(self, &impl_.generics) |
85aaf69f SL |
1658 | } |
1659 | } | |
dfeec247 | 1660 | return; |
85aaf69f SL |
1661 | } |
1662 | ||
1663 | // `type ... = ...;` can contain private types, because | |
1664 | // we're introducing a new name. | |
416331ca | 1665 | hir::ItemKind::TyAlias(..) => return, |
85aaf69f | 1666 | |
0731742a | 1667 | // Not at all public, so we don't care. |
2b03887a | 1668 | _ if !self.item_is_public(item.owner_id.def_id) => { |
c34b1796 AL |
1669 | return; |
1670 | } | |
85aaf69f SL |
1671 | |
1672 | _ => {} | |
1673 | } | |
1674 | ||
c34b1796 | 1675 | // We've carefully constructed it so that if we're here, then |
85aaf69f | 1676 | // any `visit_ty`'s will be called on things that are in |
0731742a | 1677 | // public signatures, i.e., things that we're interested in for |
85aaf69f | 1678 | // this visitor. |
92a42be0 | 1679 | intravisit::walk_item(self, item); |
85aaf69f SL |
1680 | } |
1681 | ||
dfeec247 | 1682 | fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) { |
04454e1e | 1683 | for predicate in generics.predicates { |
85aaf69f | 1684 | match predicate { |
0731742a | 1685 | hir::WherePredicate::BoundPredicate(bound_pred) => { |
62682a34 | 1686 | for bound in bound_pred.bounds.iter() { |
8faf50e0 | 1687 | self.check_generic_bound(bound) |
85aaf69f SL |
1688 | } |
1689 | } | |
0731742a XL |
1690 | hir::WherePredicate::RegionPredicate(_) => {} |
1691 | hir::WherePredicate::EqPredicate(eq_pred) => { | |
c295e0f8 | 1692 | self.visit_ty(eq_pred.rhs_ty); |
85aaf69f SL |
1693 | } |
1694 | } | |
1695 | } | |
1696 | } | |
1697 | ||
dfeec247 | 1698 | fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { |
2b03887a | 1699 | if self.effective_visibilities.is_reachable(item.owner_id.def_id) { |
92a42be0 | 1700 | intravisit::walk_foreign_item(self, item) |
85aaf69f SL |
1701 | } |
1702 | } | |
1703 | ||
dfeec247 | 1704 | fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) { |
c295e0f8 | 1705 | if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = t.kind { |
476ff2be | 1706 | if self.path_is_private_type(path) { |
532ac7d7 | 1707 | self.old_error_set.insert(t.hir_id); |
85aaf69f SL |
1708 | } |
1709 | } | |
92a42be0 | 1710 | intravisit::walk_ty(self, t) |
85aaf69f SL |
1711 | } |
1712 | ||
f2b60f7d | 1713 | fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) { |
2b03887a | 1714 | if self.effective_visibilities.is_reachable(self.tcx.hir().local_def_id(v.id)) { |
85aaf69f | 1715 | self.in_variant = true; |
f2b60f7d | 1716 | intravisit::walk_variant(self, v); |
85aaf69f SL |
1717 | self.in_variant = false; |
1718 | } | |
1719 | } | |
1720 | ||
6a06907d | 1721 | fn visit_field_def(&mut self, s: &'tcx hir::FieldDef<'tcx>) { |
04454e1e FG |
1722 | let def_id = self.tcx.hir().local_def_id(s.hir_id); |
1723 | let vis = self.tcx.visibility(def_id); | |
1724 | if vis.is_public() || self.in_variant { | |
6a06907d | 1725 | intravisit::walk_field_def(self, s); |
85aaf69f SL |
1726 | } |
1727 | } | |
1728 | ||
0731742a | 1729 | // We don't need to introspect into these at all: an |
85aaf69f SL |
1730 | // expression/block context can't possibly contain exported things. |
1731 | // (Making them no-ops stops us from traversing the whole AST without | |
1732 | // having to be super careful about our `walk_...` calls above.) | |
dfeec247 XL |
1733 | fn visit_block(&mut self, _: &'tcx hir::Block<'tcx>) {} |
1734 | fn visit_expr(&mut self, _: &'tcx hir::Expr<'tcx>) {} | |
85aaf69f SL |
1735 | } |
1736 | ||
9cc50fc6 SL |
1737 | /////////////////////////////////////////////////////////////////////////////// |
1738 | /// SearchInterfaceForPrivateItemsVisitor traverses an item's interface and | |
1739 | /// finds any private components in it. | |
1740 | /// PrivateItemsInPublicInterfacesVisitor ensures there are no private types | |
1741 | /// and traits in public interfaces. | |
1742 | /////////////////////////////////////////////////////////////////////////////// | |
1743 | ||
dc9dc135 XL |
1744 | struct SearchInterfaceForPrivateItemsVisitor<'tcx> { |
1745 | tcx: TyCtxt<'tcx>, | |
94222f64 | 1746 | item_def_id: LocalDefId, |
0731742a | 1747 | /// The visitor checks that each component type is at least this visible. |
54a0048b | 1748 | required_visibility: ty::Visibility, |
476ff2be | 1749 | has_old_errors: bool, |
ff7c6d11 | 1750 | in_assoc_ty: bool, |
9cc50fc6 SL |
1751 | } |
1752 | ||
a2a8927a | 1753 | impl SearchInterfaceForPrivateItemsVisitor<'_> { |
476ff2be | 1754 | fn generics(&mut self) -> &mut Self { |
94b46f34 XL |
1755 | for param in &self.tcx.generics_of(self.item_def_id).params { |
1756 | match param.kind { | |
532ac7d7 | 1757 | GenericParamDefKind::Lifetime => {} |
94b46f34 XL |
1758 | GenericParamDefKind::Type { has_default, .. } => { |
1759 | if has_default { | |
0731742a | 1760 | self.visit(self.tcx.type_of(param.def_id)); |
94b46f34 XL |
1761 | } |
1762 | } | |
94222f64 | 1763 | // FIXME(generic_const_exprs): May want to look inside const here |
cdc7bbd5 | 1764 | GenericParamDefKind::Const { .. } => { |
532ac7d7 XL |
1765 | self.visit(self.tcx.type_of(param.def_id)); |
1766 | } | |
8bb4bdeb XL |
1767 | } |
1768 | } | |
476ff2be | 1769 | self |
54a0048b | 1770 | } |
54a0048b | 1771 | |
476ff2be | 1772 | fn predicates(&mut self) -> &mut Self { |
0731742a | 1773 | // N.B., we use `explicit_predicates_of` and not `predicates_of` |
0bf4aa26 XL |
1774 | // because we don't want to report privacy errors due to where |
1775 | // clauses that the compiler inferred. We only want to | |
1776 | // consider the ones that the user wrote. This is important | |
1777 | // for the inferred outlives rules; see | |
1778 | // `src/test/ui/rfc-2093-infer-outlives/privacy.rs`. | |
0731742a | 1779 | self.visit_predicates(self.tcx.explicit_predicates_of(self.item_def_id)); |
476ff2be SL |
1780 | self |
1781 | } | |
1782 | ||
29967ef6 XL |
1783 | fn bounds(&mut self) -> &mut Self { |
1784 | self.visit_predicates(ty::GenericPredicates { | |
1785 | parent: None, | |
1786 | predicates: self.tcx.explicit_item_bounds(self.item_def_id), | |
1787 | }); | |
1788 | self | |
1789 | } | |
1790 | ||
7cac9316 | 1791 | fn ty(&mut self) -> &mut Self { |
0731742a | 1792 | self.visit(self.tcx.type_of(self.item_def_id)); |
476ff2be SL |
1793 | self |
1794 | } | |
1795 | ||
0731742a | 1796 | fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool { |
9fa01778 | 1797 | if self.leaks_private_dep(def_id) { |
064997fb | 1798 | self.tcx.emit_spanned_lint( |
dfeec247 | 1799 | lint::builtin::EXPORTED_PRIVATE_DEPENDENCIES, |
94222f64 XL |
1800 | self.tcx.hir().local_def_id_to_hir_id(self.item_def_id), |
1801 | self.tcx.def_span(self.item_def_id.to_def_id()), | |
064997fb FG |
1802 | FromPrivateDependencyInPublicInterface { |
1803 | kind, | |
1804 | descr: descr.into(), | |
1805 | krate: self.tcx.crate_name(def_id.krate), | |
74b04a01 | 1806 | }, |
dfeec247 | 1807 | ); |
9fa01778 XL |
1808 | } |
1809 | ||
f2b60f7d FG |
1810 | let Some(local_def_id) = def_id.as_local() else { |
1811 | return false; | |
0731742a | 1812 | }; |
041b39d2 | 1813 | |
f2b60f7d | 1814 | let vis = self.tcx.local_visibility(local_def_id); |
0731742a | 1815 | if !vis.is_at_least(self.required_visibility, self.tcx) { |
f2b60f7d | 1816 | let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id); |
29967ef6 XL |
1817 | let vis_descr = match vis { |
1818 | ty::Visibility::Public => "public", | |
29967ef6 | 1819 | ty::Visibility::Restricted(vis_def_id) => { |
f2b60f7d | 1820 | if vis_def_id == self.tcx.parent_module(hir_id) { |
29967ef6 XL |
1821 | "private" |
1822 | } else if vis_def_id.is_top_level_module() { | |
1823 | "crate-private" | |
1824 | } else { | |
1825 | "restricted" | |
1826 | } | |
1827 | } | |
1828 | }; | |
94222f64 | 1829 | let span = self.tcx.def_span(self.item_def_id.to_def_id()); |
04454e1e FG |
1830 | if self.has_old_errors |
1831 | || self.in_assoc_ty | |
1832 | || self.tcx.resolutions(()).has_pub_restricted | |
1833 | { | |
064997fb FG |
1834 | let vis_span = self.tcx.def_span(def_id); |
1835 | if kind == "trait" { | |
1836 | self.tcx.sess.emit_err(InPublicInterfaceTraits { | |
1837 | span, | |
1838 | vis_descr, | |
1839 | kind, | |
1840 | descr: descr.into(), | |
1841 | vis_span, | |
1842 | }); | |
041b39d2 | 1843 | } else { |
064997fb FG |
1844 | self.tcx.sess.emit_err(InPublicInterface { |
1845 | span, | |
1846 | vis_descr, | |
1847 | kind, | |
1848 | descr: descr.into(), | |
1849 | vis_span, | |
1850 | }); | |
1851 | } | |
0731742a | 1852 | } else { |
064997fb | 1853 | self.tcx.emit_spanned_lint( |
dfeec247 XL |
1854 | lint::builtin::PRIVATE_IN_PUBLIC, |
1855 | hir_id, | |
94222f64 | 1856 | span, |
064997fb | 1857 | PrivateInPublicLint { vis_descr, kind, descr: descr.into() }, |
dfeec247 | 1858 | ); |
041b39d2 XL |
1859 | } |
1860 | } | |
9fa01778 | 1861 | |
0731742a | 1862 | false |
041b39d2 | 1863 | } |
9fa01778 XL |
1864 | |
1865 | /// An item is 'leaked' from a private dependency if all | |
1866 | /// of the following are true: | |
1867 | /// 1. It's contained within a public type | |
1868 | /// 2. It comes from a private crate | |
1869 | fn leaks_private_dep(&self, item_id: DefId) -> bool { | |
3c0e092e | 1870 | let ret = self.required_visibility.is_public() && self.tcx.is_private_dep(item_id.krate); |
9fa01778 | 1871 | |
f2b60f7d | 1872 | debug!("leaks_private_dep(item_id={:?})={}", item_id, ret); |
ba9703b0 | 1873 | ret |
9fa01778 | 1874 | } |
9cc50fc6 SL |
1875 | } |
1876 | ||
a2a8927a | 1877 | impl<'tcx> DefIdVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'tcx> { |
dfeec247 XL |
1878 | fn tcx(&self) -> TyCtxt<'tcx> { |
1879 | self.tcx | |
1880 | } | |
29967ef6 XL |
1881 | fn visit_def_id( |
1882 | &mut self, | |
1883 | def_id: DefId, | |
1884 | kind: &str, | |
1885 | descr: &dyn fmt::Display, | |
fc512014 | 1886 | ) -> ControlFlow<Self::BreakTy> { |
29967ef6 XL |
1887 | if self.check_def_id(def_id, kind, descr) { |
1888 | ControlFlow::BREAK | |
1889 | } else { | |
1890 | ControlFlow::CONTINUE | |
1891 | } | |
9cc50fc6 | 1892 | } |
9cc50fc6 SL |
1893 | } |
1894 | ||
923072b8 | 1895 | struct PrivateItemsInPublicInterfacesChecker<'tcx> { |
dc9dc135 | 1896 | tcx: TyCtxt<'tcx>, |
94222f64 | 1897 | old_error_set_ancestry: LocalDefIdSet, |
9cc50fc6 SL |
1898 | } |
1899 | ||
923072b8 | 1900 | impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx> { |
dc9dc135 XL |
1901 | fn check( |
1902 | &self, | |
94222f64 | 1903 | def_id: LocalDefId, |
dc9dc135 XL |
1904 | required_visibility: ty::Visibility, |
1905 | ) -> SearchInterfaceForPrivateItemsVisitor<'tcx> { | |
476ff2be SL |
1906 | SearchInterfaceForPrivateItemsVisitor { |
1907 | tcx: self.tcx, | |
94222f64 | 1908 | item_def_id: def_id, |
3b2f2976 | 1909 | required_visibility, |
94222f64 | 1910 | has_old_errors: self.old_error_set_ancestry.contains(&def_id), |
ff7c6d11 | 1911 | in_assoc_ty: false, |
9fa01778 XL |
1912 | } |
1913 | } | |
1914 | ||
dc9dc135 XL |
1915 | fn check_assoc_item( |
1916 | &self, | |
94222f64 | 1917 | def_id: LocalDefId, |
dc9dc135 | 1918 | assoc_item_kind: AssocItemKind, |
dc9dc135 XL |
1919 | vis: ty::Visibility, |
1920 | ) { | |
94222f64 | 1921 | let mut check = self.check(def_id, vis); |
9fa01778 XL |
1922 | |
1923 | let (check_ty, is_assoc_ty) = match assoc_item_kind { | |
ba9703b0 | 1924 | AssocItemKind::Const | AssocItemKind::Fn { .. } => (true, false), |
064997fb | 1925 | AssocItemKind::Type => (self.tcx.impl_defaultness(def_id).has_value(), true), |
9fa01778 XL |
1926 | }; |
1927 | check.in_assoc_ty = is_assoc_ty; | |
1928 | check.generics().predicates(); | |
1929 | if check_ty { | |
1930 | check.ty(); | |
476ff2be | 1931 | } |
9cc50fc6 | 1932 | } |
dfeec247 | 1933 | |
923072b8 | 1934 | pub fn check_item(&mut self, id: ItemId) { |
476ff2be | 1935 | let tcx = self.tcx; |
2b03887a FG |
1936 | let def_id = id.owner_id.def_id; |
1937 | let item_visibility = tcx.local_visibility(def_id); | |
1938 | let def_kind = tcx.def_kind(def_id); | |
54a0048b | 1939 | |
923072b8 FG |
1940 | match def_kind { |
1941 | DefKind::Const | DefKind::Static(_) | DefKind::Fn | DefKind::TyAlias => { | |
2b03887a | 1942 | self.check(def_id, item_visibility).generics().predicates().ty(); |
0731742a | 1943 | } |
923072b8 | 1944 | DefKind::OpaqueTy => { |
416331ca | 1945 | // `ty()` for opaque types is the underlying type, |
0731742a | 1946 | // it's not a part of interface, so we skip it. |
2b03887a | 1947 | self.check(def_id, item_visibility).generics().bounds(); |
476ff2be | 1948 | } |
923072b8 FG |
1949 | DefKind::Trait => { |
1950 | let item = tcx.hir().item(id); | |
1951 | if let hir::ItemKind::Trait(.., trait_item_refs) = item.kind { | |
2b03887a | 1952 | self.check(item.owner_id.def_id, item_visibility).generics().predicates(); |
476ff2be | 1953 | |
923072b8 FG |
1954 | for trait_item_ref in trait_item_refs { |
1955 | self.check_assoc_item( | |
2b03887a | 1956 | trait_item_ref.id.owner_id.def_id, |
923072b8 | 1957 | trait_item_ref.kind, |
923072b8 FG |
1958 | item_visibility, |
1959 | ); | |
1960 | ||
1961 | if let AssocItemKind::Type = trait_item_ref.kind { | |
2b03887a | 1962 | self.check(trait_item_ref.id.owner_id.def_id, item_visibility).bounds(); |
923072b8 | 1963 | } |
29967ef6 | 1964 | } |
476ff2be SL |
1965 | } |
1966 | } | |
923072b8 | 1967 | DefKind::TraitAlias => { |
2b03887a | 1968 | self.check(def_id, item_visibility).generics().predicates(); |
ff7c6d11 | 1969 | } |
923072b8 FG |
1970 | DefKind::Enum => { |
1971 | let item = tcx.hir().item(id); | |
1972 | if let hir::ItemKind::Enum(ref def, _) = item.kind { | |
2b03887a | 1973 | self.check(item.owner_id.def_id, item_visibility).generics().predicates(); |
476ff2be | 1974 | |
923072b8 FG |
1975 | for variant in def.variants { |
1976 | for field in variant.data.fields() { | |
1977 | self.check(self.tcx.hir().local_def_id(field.hir_id), item_visibility) | |
1978 | .ty(); | |
1979 | } | |
476ff2be SL |
1980 | } |
1981 | } | |
9cc50fc6 | 1982 | } |
0731742a | 1983 | // Subitems of foreign modules have their own publicity. |
923072b8 FG |
1984 | DefKind::ForeignMod => { |
1985 | let item = tcx.hir().item(id); | |
1986 | if let hir::ItemKind::ForeignMod { items, .. } = item.kind { | |
1987 | for foreign_item in items { | |
2b03887a FG |
1988 | let vis = tcx.local_visibility(foreign_item.id.owner_id.def_id); |
1989 | self.check(foreign_item.id.owner_id.def_id, vis) | |
1990 | .generics() | |
1991 | .predicates() | |
1992 | .ty(); | |
923072b8 | 1993 | } |
9cc50fc6 SL |
1994 | } |
1995 | } | |
0731742a | 1996 | // Subitems of structs and unions have their own publicity. |
923072b8 FG |
1997 | DefKind::Struct | DefKind::Union => { |
1998 | let item = tcx.hir().item(id); | |
1999 | if let hir::ItemKind::Struct(ref struct_def, _) | |
2000 | | hir::ItemKind::Union(ref struct_def, _) = item.kind | |
2001 | { | |
2b03887a | 2002 | self.check(item.owner_id.def_id, item_visibility).generics().predicates(); |
54a0048b | 2003 | |
923072b8 FG |
2004 | for field in struct_def.fields() { |
2005 | let def_id = tcx.hir().local_def_id(field.hir_id); | |
f2b60f7d | 2006 | let field_visibility = tcx.local_visibility(def_id); |
923072b8 FG |
2007 | self.check(def_id, min(item_visibility, field_visibility, tcx)).ty(); |
2008 | } | |
9cc50fc6 SL |
2009 | } |
2010 | } | |
9cc50fc6 | 2011 | // An inherent impl is public when its type is public |
0731742a | 2012 | // Subitems of inherent impls have their own publicity. |
9cc50fc6 | 2013 | // A trait impl is public when both its type and its trait are public |
0731742a | 2014 | // Subitems of trait impls have inherited publicity. |
923072b8 FG |
2015 | DefKind::Impl => { |
2016 | let item = tcx.hir().item(id); | |
2017 | if let hir::ItemKind::Impl(ref impl_) = item.kind { | |
2b03887a FG |
2018 | let impl_vis = |
2019 | ty::Visibility::of_impl(item.owner_id.def_id, tcx, &Default::default()); | |
923072b8 FG |
2020 | // check that private components do not appear in the generics or predicates of inherent impls |
2021 | // this check is intentionally NOT performed for impls of traits, per #90586 | |
2022 | if impl_.of_trait.is_none() { | |
2b03887a | 2023 | self.check(item.owner_id.def_id, impl_vis).generics().predicates(); |
923072b8 FG |
2024 | } |
2025 | for impl_item_ref in impl_.items { | |
2026 | let impl_item_vis = if impl_.of_trait.is_none() { | |
2b03887a FG |
2027 | min( |
2028 | tcx.local_visibility(impl_item_ref.id.owner_id.def_id), | |
2029 | impl_vis, | |
2030 | tcx, | |
2031 | ) | |
923072b8 FG |
2032 | } else { |
2033 | impl_vis | |
2034 | }; | |
2035 | self.check_assoc_item( | |
2b03887a | 2036 | impl_item_ref.id.owner_id.def_id, |
923072b8 | 2037 | impl_item_ref.kind, |
923072b8 FG |
2038 | impl_item_vis, |
2039 | ); | |
2040 | } | |
9cc50fc6 SL |
2041 | } |
2042 | } | |
923072b8 | 2043 | _ => {} |
9cc50fc6 SL |
2044 | } |
2045 | } | |
2046 | } | |
2047 | ||
f035d41b | 2048 | pub fn provide(providers: &mut Providers) { |
cc61c64b | 2049 | *providers = Providers { |
29967ef6 | 2050 | visibility, |
2b03887a | 2051 | effective_visibilities, |
532ac7d7 | 2052 | check_private_in_public, |
9fa01778 | 2053 | check_mod_privacy, |
cc61c64b XL |
2054 | ..*providers |
2055 | }; | |
2056 | } | |
2057 | ||
f2b60f7d FG |
2058 | fn visibility(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Visibility<DefId> { |
2059 | local_visibility(tcx, def_id.expect_local()).to_def_id() | |
2060 | } | |
2061 | ||
2062 | fn local_visibility(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Visibility { | |
136023e0 | 2063 | match tcx.resolutions(()).visibilities.get(&def_id) { |
29967ef6 XL |
2064 | Some(vis) => *vis, |
2065 | None => { | |
2066 | let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); | |
2067 | match tcx.hir().get(hir_id) { | |
2068 | // Unique types created for closures participate in type privacy checking. | |
2069 | // They have visibilities inherited from the module they are defined in. | |
923072b8 | 2070 | Node::Expr(hir::Expr { kind: hir::ExprKind::Closure{..}, .. }) |
04454e1e | 2071 | // - AST lowering creates dummy `use` items which don't |
29967ef6 | 2072 | // get their entries in the resolver's visibility table. |
5e7ed085 | 2073 | // - AST lowering also creates opaque type items with inherited visibilities. |
29967ef6 XL |
2074 | // Visibility on them should have no effect, but to avoid the visibility |
2075 | // query failing on some items, we provide it for opaque types as well. | |
04454e1e | 2076 | | Node::Item(hir::Item { |
f2b60f7d FG |
2077 | kind: hir::ItemKind::Use(_, hir::UseKind::ListStem) |
2078 | | hir::ItemKind::OpaqueTy(..), | |
29967ef6 | 2079 | .. |
f2b60f7d | 2080 | }) => ty::Visibility::Restricted(tcx.parent_module(hir_id)), |
29967ef6 XL |
2081 | // Visibilities of trait impl items are inherited from their traits |
2082 | // and are not filled in resolve. | |
2083 | Node::ImplItem(impl_item) => { | |
2b03887a | 2084 | match tcx.hir().get_by_def_id(tcx.hir().get_parent_item(hir_id).def_id) { |
29967ef6 | 2085 | Node::Item(hir::Item { |
5869c6ff | 2086 | kind: hir::ItemKind::Impl(hir::Impl { of_trait: Some(tr), .. }), |
29967ef6 XL |
2087 | .. |
2088 | }) => tr.path.res.opt_def_id().map_or_else( | |
2089 | || { | |
2090 | tcx.sess.delay_span_bug(tr.path.span, "trait without a def-id"); | |
2091 | ty::Visibility::Public | |
2092 | }, | |
f2b60f7d | 2093 | |def_id| tcx.visibility(def_id).expect_local(), |
29967ef6 XL |
2094 | ), |
2095 | _ => span_bug!(impl_item.span, "the parent is not a trait impl"), | |
2096 | } | |
2097 | } | |
2098 | _ => span_bug!( | |
2099 | tcx.def_span(def_id), | |
2100 | "visibility table unexpectedly missing a def-id: {:?}", | |
2101 | def_id, | |
2102 | ), | |
2103 | } | |
2104 | } | |
2105 | } | |
2106 | } | |
2107 | ||
f9f354fc | 2108 | fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { |
7cac9316 | 2109 | // Check privacy of names not checked in previous compilation stages. |
94222f64 XL |
2110 | let mut visitor = |
2111 | NamePrivacyVisitor { tcx, maybe_typeck_results: None, current_item: module_def_id }; | |
532ac7d7 | 2112 | let (module, span, hir_id) = tcx.hir().get_module(module_def_id); |
48663c56 | 2113 | |
9fa01778 | 2114 | intravisit::walk_mod(&mut visitor, module, hir_id); |
85aaf69f | 2115 | |
041b39d2 XL |
2116 | // Check privacy of explicitly written types and traits as well as |
2117 | // inferred types of expressions and patterns. | |
f035d41b | 2118 | let mut visitor = |
3dfed10e | 2119 | TypePrivacyVisitor { tcx, maybe_typeck_results: None, current_item: module_def_id, span }; |
9fa01778 XL |
2120 | intravisit::walk_mod(&mut visitor, module, hir_id); |
2121 | } | |
2122 | ||
2b03887a | 2123 | fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities { |
85aaf69f SL |
2124 | // Build up a set of all exported items in the AST. This is a set of all |
2125 | // items which are reachable from external crates based on visibility. | |
2126 | let mut visitor = EmbargoVisitor { | |
3b2f2976 | 2127 | tcx, |
2b03887a | 2128 | effective_visibilities: tcx.resolutions(()).effective_visibilities.clone(), |
416331ca | 2129 | macro_reachable: Default::default(), |
2b03887a | 2130 | prev_level: Some(Level::Direct), |
92a42be0 | 2131 | changed: false, |
85aaf69f | 2132 | }; |
5099ac24 | 2133 | |
85aaf69f | 2134 | loop { |
c295e0f8 | 2135 | tcx.hir().walk_toplevel_module(&mut visitor); |
92a42be0 SL |
2136 | if visitor.changed { |
2137 | visitor.changed = false; | |
2138 | } else { | |
dfeec247 | 2139 | break; |
85aaf69f SL |
2140 | } |
2141 | } | |
2142 | ||
2b03887a FG |
2143 | let mut check_visitor = |
2144 | TestReachabilityVisitor { tcx, effective_visibilities: &visitor.effective_visibilities }; | |
f2b60f7d FG |
2145 | tcx.hir().visit_all_item_likes_in_crate(&mut check_visitor); |
2146 | ||
2b03887a | 2147 | tcx.arena.alloc(visitor.effective_visibilities) |
532ac7d7 | 2148 | } |
9cc50fc6 | 2149 | |
17df50a5 | 2150 | fn check_private_in_public(tcx: TyCtxt<'_>, (): ()) { |
2b03887a | 2151 | let effective_visibilities = tcx.effective_visibilities(()); |
532ac7d7 | 2152 | |
532ac7d7 XL |
2153 | let mut visitor = ObsoleteVisiblePrivateTypesVisitor { |
2154 | tcx, | |
2b03887a | 2155 | effective_visibilities, |
532ac7d7 XL |
2156 | in_variant: false, |
2157 | old_error_set: Default::default(), | |
2158 | }; | |
c295e0f8 | 2159 | tcx.hir().walk_toplevel_module(&mut visitor); |
532ac7d7 | 2160 | |
6a06907d XL |
2161 | let mut old_error_set_ancestry = HirIdSet::default(); |
2162 | for mut id in visitor.old_error_set.iter().copied() { | |
2163 | loop { | |
2164 | if !old_error_set_ancestry.insert(id) { | |
2165 | break; | |
2166 | } | |
2167 | let parent = tcx.hir().get_parent_node(id); | |
2168 | if parent == id { | |
2169 | break; | |
2170 | } | |
2171 | id = parent; | |
2172 | } | |
2173 | } | |
2174 | ||
532ac7d7 | 2175 | // Check for private types and traits in public interfaces. |
923072b8 | 2176 | let mut checker = PrivateItemsInPublicInterfacesChecker { |
94222f64 | 2177 | tcx, |
94222f64 XL |
2178 | // Only definition IDs are ever searched in `old_error_set_ancestry`, |
2179 | // so we can filter away all non-definition IDs at this point. | |
2180 | old_error_set_ancestry: old_error_set_ancestry | |
2181 | .into_iter() | |
2182 | .filter_map(|hir_id| tcx.hir().opt_local_def_id(hir_id)) | |
2183 | .collect(), | |
2184 | }; | |
923072b8 FG |
2185 | |
2186 | for id in tcx.hir().items() { | |
2187 | checker.check_item(id); | |
2188 | } | |
85aaf69f | 2189 | } |