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