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