1#![allow(internal_features)]
3#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
4#![doc(rust_logo)]
5#![feature(associated_type_defaults)]
6#![feature(let_chains)]
7#![feature(rustdoc_internals)]
8#![feature(try_blocks)]
9#![warn(unreachable_pub)]
10mod errors;
13
14use std::fmt;
15use std::marker::PhantomData;
16use std::ops::ControlFlow;
17
18use errors::{
19 FieldIsPrivate, FieldIsPrivateLabel, FromPrivateDependencyInPublicInterface, InPublicInterface,
20 ItemIsPrivate, PrivateInterfacesOrBoundsLint, ReportEffectiveVisibility, UnnameableTypesLint,
21 UnnamedItemIsPrivate,
22};
23use rustc_ast::MacroDef;
24use rustc_ast::visit::{VisitorResult, try_visit};
25use rustc_data_structures::fx::FxHashSet;
26use rustc_data_structures::intern::Interned;
27use rustc_errors::{MultiSpan, listify};
28use rustc_hir::def::{DefKind, Res};
29use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId, LocalModDefId};
30use rustc_hir::intravisit::{self, InferKind, Visitor};
31use rustc_hir::{AmbigArg, AssocItemKind, ForeignItemKind, ItemId, ItemKind, PatKind};
32use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, Level};
33use rustc_middle::query::Providers;
34use rustc_middle::ty::print::PrintTraitRefExt as _;
35use rustc_middle::ty::{
36 self, Const, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
37 TypeVisitor,
38};
39use rustc_middle::{bug, span_bug};
40use rustc_session::lint;
41use rustc_span::hygiene::Transparency;
42use rustc_span::{Ident, Span, Symbol, kw, sym};
43use tracing::debug;
44use {rustc_attr_parsing as attr, rustc_hir as hir};
45
46rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
47
48struct LazyDefPathStr<'tcx> {
53 def_id: DefId,
54 tcx: TyCtxt<'tcx>,
55}
56
57impl<'tcx> fmt::Display for LazyDefPathStr<'tcx> {
58 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59 write!(f, "{}", self.tcx.def_path_str(self.def_id))
60 }
61}
62
63pub trait DefIdVisitor<'tcx> {
72 type Result: VisitorResult = ();
73 const SHALLOW: bool = false;
74 const SKIP_ASSOC_TYS: bool = false;
75
76 fn tcx(&self) -> TyCtxt<'tcx>;
77 fn visit_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display)
78 -> Self::Result;
79
80 fn skeleton(&mut self) -> DefIdVisitorSkeleton<'_, 'tcx, Self> {
82 DefIdVisitorSkeleton {
83 def_id_visitor: self,
84 visited_opaque_tys: Default::default(),
85 dummy: Default::default(),
86 }
87 }
88 fn visit(&mut self, ty_fragment: impl TypeVisitable<TyCtxt<'tcx>>) -> Self::Result {
89 ty_fragment.visit_with(&mut self.skeleton())
90 }
91 fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> Self::Result {
92 self.skeleton().visit_trait(trait_ref)
93 }
94 fn visit_predicates(&mut self, predicates: ty::GenericPredicates<'tcx>) -> Self::Result {
95 self.skeleton().visit_clauses(predicates.predicates)
96 }
97 fn visit_clauses(&mut self, clauses: &[(ty::Clause<'tcx>, Span)]) -> Self::Result {
98 self.skeleton().visit_clauses(clauses)
99 }
100}
101
102pub struct DefIdVisitorSkeleton<'v, 'tcx, V: ?Sized> {
103 def_id_visitor: &'v mut V,
104 visited_opaque_tys: FxHashSet<DefId>,
105 dummy: PhantomData<TyCtxt<'tcx>>,
106}
107
108impl<'tcx, V> DefIdVisitorSkeleton<'_, 'tcx, V>
109where
110 V: DefIdVisitor<'tcx> + ?Sized,
111{
112 fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> V::Result {
113 let TraitRef { def_id, args, .. } = trait_ref;
114 try_visit!(self.def_id_visitor.visit_def_id(
115 def_id,
116 "trait",
117 &trait_ref.print_only_trait_path()
118 ));
119 if V::SHALLOW { V::Result::output() } else { args.visit_with(self) }
120 }
121
122 fn visit_projection_term(&mut self, projection: ty::AliasTerm<'tcx>) -> V::Result {
123 let tcx = self.def_id_visitor.tcx();
124 let (trait_ref, assoc_args) = projection.trait_ref_and_own_args(tcx);
125 try_visit!(self.visit_trait(trait_ref));
126 if V::SHALLOW {
127 V::Result::output()
128 } else {
129 V::Result::from_branch(
130 assoc_args.iter().try_for_each(|arg| arg.visit_with(self).branch()),
131 )
132 }
133 }
134
135 fn visit_clause(&mut self, clause: ty::Clause<'tcx>) -> V::Result {
136 match clause.kind().skip_binder() {
137 ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity: _ }) => {
138 self.visit_trait(trait_ref)
139 }
140 ty::ClauseKind::HostEffect(pred) => {
141 try_visit!(self.visit_trait(pred.trait_ref));
142 pred.constness.visit_with(self)
143 }
144 ty::ClauseKind::Projection(ty::ProjectionPredicate {
145 projection_term: projection_ty,
146 term,
147 }) => {
148 try_visit!(term.visit_with(self));
149 self.visit_projection_term(projection_ty)
150 }
151 ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, _region)) => ty.visit_with(self),
152 ty::ClauseKind::RegionOutlives(..) => V::Result::output(),
153 ty::ClauseKind::ConstArgHasType(ct, ty) => {
154 try_visit!(ct.visit_with(self));
155 ty.visit_with(self)
156 }
157 ty::ClauseKind::ConstEvaluatable(ct) => ct.visit_with(self),
158 ty::ClauseKind::WellFormed(arg) => arg.visit_with(self),
159 }
160 }
161
162 fn visit_clauses(&mut self, clauses: &[(ty::Clause<'tcx>, Span)]) -> V::Result {
163 for &(clause, _) in clauses {
164 try_visit!(self.visit_clause(clause));
165 }
166 V::Result::output()
167 }
168}
169
170impl<'tcx, V> TypeVisitor<TyCtxt<'tcx>> for DefIdVisitorSkeleton<'_, 'tcx, V>
171where
172 V: DefIdVisitor<'tcx> + ?Sized,
173{
174 type Result = V::Result;
175
176 fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> Self::Result {
177 self.visit_clause(p.as_clause().unwrap())
178 }
179
180 fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
181 let tcx = self.def_id_visitor.tcx();
182 match *ty.kind() {
185 ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), ..)
186 | ty::Foreign(def_id)
187 | ty::FnDef(def_id, ..)
188 | ty::Closure(def_id, ..)
189 | ty::CoroutineClosure(def_id, ..)
190 | ty::Coroutine(def_id, ..) => {
191 try_visit!(self.def_id_visitor.visit_def_id(def_id, "type", &ty));
192 if V::SHALLOW {
193 return V::Result::output();
194 }
195 if let ty::FnDef(..) = ty.kind() {
199 try_visit!(tcx.fn_sig(def_id).instantiate_identity().visit_with(self));
201 }
202 if let Some(assoc_item) = tcx.opt_associated_item(def_id) {
207 if let Some(impl_def_id) = assoc_item.impl_container(tcx) {
208 try_visit!(
209 tcx.type_of(impl_def_id).instantiate_identity().visit_with(self)
210 );
211 }
212 }
213 }
214 ty::Alias(kind @ (ty::Inherent | ty::Weak | ty::Projection), data) => {
215 if V::SKIP_ASSOC_TYS {
216 return V::Result::output();
222 }
223
224 try_visit!(self.def_id_visitor.visit_def_id(
225 data.def_id,
226 match kind {
227 ty::Inherent | ty::Projection => "associated type",
228 ty::Weak => "type alias",
229 ty::Opaque => unreachable!(),
230 },
231 &LazyDefPathStr { def_id: data.def_id, tcx },
232 ));
233
234 return if V::SHALLOW {
236 V::Result::output()
237 } else if kind == ty::Projection {
238 self.visit_projection_term(data.into())
239 } else {
240 V::Result::from_branch(
241 data.args.iter().try_for_each(|arg| arg.visit_with(self).branch()),
242 )
243 };
244 }
245 ty::Dynamic(predicates, ..) => {
246 for predicate in predicates {
249 let trait_ref = match predicate.skip_binder() {
250 ty::ExistentialPredicate::Trait(trait_ref) => trait_ref,
251 ty::ExistentialPredicate::Projection(proj) => proj.trait_ref(tcx),
252 ty::ExistentialPredicate::AutoTrait(def_id) => {
253 ty::ExistentialTraitRef::new(tcx, def_id, ty::GenericArgs::empty())
254 }
255 };
256 let ty::ExistentialTraitRef { def_id, .. } = trait_ref;
257 try_visit!(self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref));
258 }
259 }
260 ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
261 if self.visited_opaque_tys.insert(def_id) {
263 try_visit!(self.visit_clauses(tcx.explicit_item_bounds(def_id).skip_binder()));
271 }
272 }
273 ty::Bool
276 | ty::Char
277 | ty::Int(..)
278 | ty::Uint(..)
279 | ty::Float(..)
280 | ty::Str
281 | ty::Never
282 | ty::Array(..)
283 | ty::Slice(..)
284 | ty::Tuple(..)
285 | ty::RawPtr(..)
286 | ty::Ref(..)
287 | ty::Pat(..)
288 | ty::FnPtr(..)
289 | ty::UnsafeBinder(_)
290 | ty::Param(..)
291 | ty::Bound(..)
292 | ty::Error(_)
293 | ty::CoroutineWitness(..) => {}
294 ty::Placeholder(..) | ty::Infer(..) => {
295 bug!("unexpected type: {:?}", ty)
296 }
297 }
298
299 if V::SHALLOW { V::Result::output() } else { ty.super_visit_with(self) }
300 }
301
302 fn visit_const(&mut self, c: Const<'tcx>) -> Self::Result {
303 let tcx = self.def_id_visitor.tcx();
304 tcx.expand_abstract_consts(c).super_visit_with(self)
305 }
306}
307
308fn min(vis1: ty::Visibility, vis2: ty::Visibility, tcx: TyCtxt<'_>) -> ty::Visibility {
309 if vis1.is_at_least(vis2, tcx) { vis2 } else { vis1 }
310}
311
312struct FindMin<'a, 'tcx, VL: VisibilityLike, const SHALLOW: bool> {
317 tcx: TyCtxt<'tcx>,
318 effective_visibilities: &'a EffectiveVisibilities,
319 min: VL,
320}
321
322impl<'a, 'tcx, VL: VisibilityLike, const SHALLOW: bool> DefIdVisitor<'tcx>
323 for FindMin<'a, 'tcx, VL, SHALLOW>
324{
325 const SHALLOW: bool = SHALLOW;
326 const SKIP_ASSOC_TYS: bool = true;
327 fn tcx(&self) -> TyCtxt<'tcx> {
328 self.tcx
329 }
330 fn visit_def_id(&mut self, def_id: DefId, _kind: &str, _descr: &dyn fmt::Display) {
331 if let Some(def_id) = def_id.as_local() {
332 self.min = VL::new_min(self, def_id);
333 }
334 }
335}
336
337trait VisibilityLike: Sized {
338 const MAX: Self;
339 fn new_min<const SHALLOW: bool>(
340 find: &FindMin<'_, '_, Self, SHALLOW>,
341 def_id: LocalDefId,
342 ) -> Self;
343
344 fn of_impl<const SHALLOW: bool>(
347 def_id: LocalDefId,
348 tcx: TyCtxt<'_>,
349 effective_visibilities: &EffectiveVisibilities,
350 ) -> Self {
351 let mut find = FindMin::<_, SHALLOW> { tcx, effective_visibilities, min: Self::MAX };
352 find.visit(tcx.type_of(def_id).instantiate_identity());
353 if let Some(trait_ref) = tcx.impl_trait_ref(def_id) {
354 find.visit_trait(trait_ref.instantiate_identity());
355 }
356 find.min
357 }
358}
359
360impl VisibilityLike for ty::Visibility {
361 const MAX: Self = ty::Visibility::Public;
362 fn new_min<const SHALLOW: bool>(
363 find: &FindMin<'_, '_, Self, SHALLOW>,
364 def_id: LocalDefId,
365 ) -> Self {
366 min(find.tcx.local_visibility(def_id), find.min, find.tcx)
367 }
368}
369
370impl VisibilityLike for EffectiveVisibility {
371 const MAX: Self = EffectiveVisibility::from_vis(ty::Visibility::Public);
372 fn new_min<const SHALLOW: bool>(
373 find: &FindMin<'_, '_, Self, SHALLOW>,
374 def_id: LocalDefId,
375 ) -> Self {
376 let effective_vis =
377 find.effective_visibilities.effective_vis(def_id).copied().unwrap_or_else(|| {
378 let private_vis = ty::Visibility::Restricted(
379 find.tcx.parent_module_from_def_id(def_id).to_local_def_id(),
380 );
381 EffectiveVisibility::from_vis(private_vis)
382 });
383
384 effective_vis.min(find.min, find.tcx)
385 }
386}
387
388struct EmbargoVisitor<'tcx> {
393 tcx: TyCtxt<'tcx>,
394
395 effective_visibilities: EffectiveVisibilities,
397 macro_reachable: FxHashSet<(LocalModDefId, LocalModDefId)>,
410 changed: bool,
412}
413
414struct ReachEverythingInTheInterfaceVisitor<'a, 'tcx> {
415 effective_vis: EffectiveVisibility,
416 item_def_id: LocalDefId,
417 ev: &'a mut EmbargoVisitor<'tcx>,
418 level: Level,
419}
420
421impl<'tcx> EmbargoVisitor<'tcx> {
422 fn get(&self, def_id: LocalDefId) -> Option<EffectiveVisibility> {
423 self.effective_visibilities.effective_vis(def_id).copied()
424 }
425
426 fn update(
428 &mut self,
429 def_id: LocalDefId,
430 inherited_effective_vis: EffectiveVisibility,
431 level: Level,
432 ) {
433 let nominal_vis = self.tcx.local_visibility(def_id);
434 self.update_eff_vis(def_id, inherited_effective_vis, Some(nominal_vis), level);
435 }
436
437 fn update_eff_vis(
438 &mut self,
439 def_id: LocalDefId,
440 inherited_effective_vis: EffectiveVisibility,
441 max_vis: Option<ty::Visibility>,
442 level: Level,
443 ) {
444 let private_vis =
446 ty::Visibility::Restricted(self.tcx.parent_module_from_def_id(def_id).into());
447 if max_vis != Some(private_vis) {
448 self.changed |= self.effective_visibilities.update(
449 def_id,
450 max_vis,
451 || private_vis,
452 inherited_effective_vis,
453 level,
454 self.tcx,
455 );
456 }
457 }
458
459 fn reach(
460 &mut self,
461 def_id: LocalDefId,
462 effective_vis: EffectiveVisibility,
463 ) -> ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
464 ReachEverythingInTheInterfaceVisitor {
465 effective_vis,
466 item_def_id: def_id,
467 ev: self,
468 level: Level::Reachable,
469 }
470 }
471
472 fn reach_through_impl_trait(
473 &mut self,
474 def_id: LocalDefId,
475 effective_vis: EffectiveVisibility,
476 ) -> ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
477 ReachEverythingInTheInterfaceVisitor {
478 effective_vis,
479 item_def_id: def_id,
480 ev: self,
481 level: Level::ReachableThroughImplTrait,
482 }
483 }
484
485 fn update_reachability_from_macro(
488 &mut self,
489 local_def_id: LocalDefId,
490 md: &MacroDef,
491 macro_ev: EffectiveVisibility,
492 ) {
493 let hir_id = self.tcx.local_def_id_to_hir_id(local_def_id);
495 let attrs = self.tcx.hir().attrs(hir_id);
496 if attr::find_transparency(attrs, md.macro_rules).0 != Transparency::Opaque {
497 return;
498 }
499
500 let macro_module_def_id = self.tcx.local_parent(local_def_id);
501 if self.tcx.def_kind(macro_module_def_id) != DefKind::Mod {
502 return;
504 }
505 let macro_module_def_id = LocalModDefId::new_unchecked(macro_module_def_id);
507
508 if self.effective_visibilities.public_at_level(local_def_id).is_none() {
509 return;
510 }
511
512 let mut module_def_id = macro_module_def_id;
515 loop {
516 let changed_reachability =
517 self.update_macro_reachable(module_def_id, macro_module_def_id, macro_ev);
518 if changed_reachability || module_def_id == LocalModDefId::CRATE_DEF_ID {
519 break;
520 }
521 module_def_id = LocalModDefId::new_unchecked(self.tcx.local_parent(module_def_id));
522 }
523 }
524
525 fn update_macro_reachable(
528 &mut self,
529 module_def_id: LocalModDefId,
530 defining_mod: LocalModDefId,
531 macro_ev: EffectiveVisibility,
532 ) -> bool {
533 if self.macro_reachable.insert((module_def_id, defining_mod)) {
534 for child in self.tcx.module_children_local(module_def_id.to_local_def_id()) {
535 if let Res::Def(def_kind, def_id) = child.res
536 && let Some(def_id) = def_id.as_local()
537 && child.vis.is_accessible_from(defining_mod, self.tcx)
538 {
539 let vis = self.tcx.local_visibility(def_id);
540 self.update_macro_reachable_def(def_id, def_kind, vis, defining_mod, macro_ev);
541 }
542 }
543 true
544 } else {
545 false
546 }
547 }
548
549 fn update_macro_reachable_def(
550 &mut self,
551 def_id: LocalDefId,
552 def_kind: DefKind,
553 vis: ty::Visibility,
554 module: LocalModDefId,
555 macro_ev: EffectiveVisibility,
556 ) {
557 self.update(def_id, macro_ev, Level::Reachable);
558 match def_kind {
559 DefKind::Const | DefKind::Static { .. } | DefKind::TraitAlias | DefKind::TyAlias => {
561 if vis.is_accessible_from(module, self.tcx) {
562 self.update(def_id, macro_ev, Level::Reachable);
563 }
564 }
565
566 DefKind::Macro(_) => {
571 let item = self.tcx.hir().expect_item(def_id);
572 if let hir::ItemKind::Macro(MacroDef { macro_rules: false, .. }, _) = item.kind {
573 if vis.is_accessible_from(module, self.tcx) {
574 self.update(def_id, macro_ev, Level::Reachable);
575 }
576 }
577 }
578
579 DefKind::Mod => {
584 if vis.is_accessible_from(module, self.tcx) {
585 self.update_macro_reachable(
586 LocalModDefId::new_unchecked(def_id),
587 module,
588 macro_ev,
589 );
590 }
591 }
592
593 DefKind::Struct | DefKind::Union => {
594 let item = self.tcx.hir().expect_item(def_id);
596 if let hir::ItemKind::Struct(ref struct_def, _)
597 | hir::ItemKind::Union(ref struct_def, _) = item.kind
598 {
599 for field in struct_def.fields() {
600 let field_vis = self.tcx.local_visibility(field.def_id);
601 if field_vis.is_accessible_from(module, self.tcx) {
602 self.reach(field.def_id, macro_ev).ty();
603 }
604 }
605 } else {
606 bug!("item {:?} with DefKind {:?}", item, def_kind);
607 }
608 }
609
610 DefKind::AssocConst
613 | DefKind::AssocTy
614 | DefKind::ConstParam
615 | DefKind::Ctor(_, _)
616 | DefKind::Enum
617 | DefKind::ForeignTy
618 | DefKind::Fn
619 | DefKind::OpaqueTy
620 | DefKind::AssocFn
621 | DefKind::Trait
622 | DefKind::TyParam
623 | DefKind::Variant
624 | DefKind::LifetimeParam
625 | DefKind::ExternCrate
626 | DefKind::Use
627 | DefKind::ForeignMod
628 | DefKind::AnonConst
629 | DefKind::InlineConst
630 | DefKind::Field
631 | DefKind::GlobalAsm
632 | DefKind::Impl { .. }
633 | DefKind::Closure
634 | DefKind::SyntheticCoroutineBody => (),
635 }
636 }
637}
638
639impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
640 fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
641 let item_ev = self.get(item.owner_id.def_id);
644 match item.kind {
645 hir::ItemKind::Use(..)
647 | hir::ItemKind::ExternCrate(..)
648 | hir::ItemKind::GlobalAsm(..) => {}
649 hir::ItemKind::Mod(..) => {}
651 hir::ItemKind::Macro(macro_def, _) => {
652 if let Some(item_ev) = item_ev {
653 self.update_reachability_from_macro(item.owner_id.def_id, macro_def, item_ev);
654 }
655 }
656 hir::ItemKind::Const(..)
657 | hir::ItemKind::Static(..)
658 | hir::ItemKind::Fn { .. }
659 | hir::ItemKind::TyAlias(..) => {
660 if let Some(item_ev) = item_ev {
661 self.reach(item.owner_id.def_id, item_ev).generics().predicates().ty();
662 }
663 }
664 hir::ItemKind::Trait(.., trait_item_refs) => {
665 if let Some(item_ev) = item_ev {
666 self.reach(item.owner_id.def_id, item_ev).generics().predicates();
667
668 for trait_item_ref in trait_item_refs {
669 self.update(trait_item_ref.id.owner_id.def_id, item_ev, Level::Reachable);
670
671 let tcx = self.tcx;
672 let mut reach = self.reach(trait_item_ref.id.owner_id.def_id, item_ev);
673 reach.generics().predicates();
674
675 if trait_item_ref.kind == AssocItemKind::Type
676 && !tcx.defaultness(trait_item_ref.id.owner_id).has_value()
677 {
678 } else {
680 reach.ty();
681 }
682 }
683 }
684 }
685 hir::ItemKind::TraitAlias(..) => {
686 if let Some(item_ev) = item_ev {
687 self.reach(item.owner_id.def_id, item_ev).generics().predicates();
688 }
689 }
690 hir::ItemKind::Impl(impl_) => {
691 let item_ev = EffectiveVisibility::of_impl::<true>(
702 item.owner_id.def_id,
703 self.tcx,
704 &self.effective_visibilities,
705 );
706
707 self.update_eff_vis(item.owner_id.def_id, item_ev, None, Level::Direct);
708
709 self.reach(item.owner_id.def_id, item_ev).generics().predicates().ty().trait_ref();
710
711 for impl_item_ref in impl_.items {
712 let def_id = impl_item_ref.id.owner_id.def_id;
713 let max_vis =
714 impl_.of_trait.is_none().then(|| self.tcx.local_visibility(def_id));
715 self.update_eff_vis(def_id, item_ev, max_vis, Level::Direct);
716
717 if let Some(impl_item_ev) = self.get(def_id) {
718 self.reach(def_id, impl_item_ev).generics().predicates().ty();
719 }
720 }
721 }
722 hir::ItemKind::Enum(ref def, _) => {
723 if let Some(item_ev) = item_ev {
724 self.reach(item.owner_id.def_id, item_ev).generics().predicates();
725 }
726 for variant in def.variants {
727 if let Some(item_ev) = item_ev {
728 self.update(variant.def_id, item_ev, Level::Reachable);
729 }
730
731 if let Some(variant_ev) = self.get(variant.def_id) {
732 if let Some(ctor_def_id) = variant.data.ctor_def_id() {
733 self.update(ctor_def_id, variant_ev, Level::Reachable);
734 }
735 for field in variant.data.fields() {
736 self.update(field.def_id, variant_ev, Level::Reachable);
737 self.reach(field.def_id, variant_ev).ty();
738 }
739 self.reach(item.owner_id.def_id, variant_ev).ty();
742 }
743 if let Some(ctor_def_id) = variant.data.ctor_def_id() {
744 if let Some(ctor_ev) = self.get(ctor_def_id) {
745 self.reach(item.owner_id.def_id, ctor_ev).ty();
746 }
747 }
748 }
749 }
750 hir::ItemKind::ForeignMod { items, .. } => {
751 for foreign_item in items {
752 if let Some(foreign_item_ev) = self.get(foreign_item.id.owner_id.def_id) {
753 self.reach(foreign_item.id.owner_id.def_id, foreign_item_ev)
754 .generics()
755 .predicates()
756 .ty();
757 }
758 }
759 }
760 hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => {
761 if let Some(item_ev) = item_ev {
762 self.reach(item.owner_id.def_id, item_ev).generics().predicates();
763 for field in struct_def.fields() {
764 self.update(field.def_id, item_ev, Level::Reachable);
765 if let Some(field_ev) = self.get(field.def_id) {
766 self.reach(field.def_id, field_ev).ty();
767 }
768 }
769 }
770 if let Some(ctor_def_id) = struct_def.ctor_def_id() {
771 if let Some(item_ev) = item_ev {
772 self.update(ctor_def_id, item_ev, Level::Reachable);
773 }
774 if let Some(ctor_ev) = self.get(ctor_def_id) {
775 self.reach(item.owner_id.def_id, ctor_ev).ty();
776 }
777 }
778 }
779 }
780 }
781}
782
783impl ReachEverythingInTheInterfaceVisitor<'_, '_> {
784 fn generics(&mut self) -> &mut Self {
785 for param in &self.ev.tcx.generics_of(self.item_def_id).own_params {
786 if let GenericParamDefKind::Const { .. } = param.kind {
787 self.visit(self.ev.tcx.type_of(param.def_id).instantiate_identity());
788 }
789 if let Some(default) = param.default_value(self.ev.tcx) {
790 self.visit(default.instantiate_identity());
791 }
792 }
793 self
794 }
795
796 fn predicates(&mut self) -> &mut Self {
797 self.visit_predicates(self.ev.tcx.predicates_of(self.item_def_id));
798 self
799 }
800
801 fn ty(&mut self) -> &mut Self {
802 self.visit(self.ev.tcx.type_of(self.item_def_id).instantiate_identity());
803 self
804 }
805
806 fn trait_ref(&mut self) -> &mut Self {
807 if let Some(trait_ref) = self.ev.tcx.impl_trait_ref(self.item_def_id) {
808 self.visit_trait(trait_ref.instantiate_identity());
809 }
810 self
811 }
812}
813
814impl<'tcx> DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
815 fn tcx(&self) -> TyCtxt<'tcx> {
816 self.ev.tcx
817 }
818 fn visit_def_id(&mut self, def_id: DefId, _kind: &str, _descr: &dyn fmt::Display) {
819 if let Some(def_id) = def_id.as_local() {
820 let max_vis = (self.level != Level::ReachableThroughImplTrait)
824 .then(|| self.ev.tcx.local_visibility(def_id));
825 self.ev.update_eff_vis(def_id, self.effective_vis, max_vis, self.level);
826 }
827 }
828}
829
830pub struct TestReachabilityVisitor<'a, 'tcx> {
834 tcx: TyCtxt<'tcx>,
835 effective_visibilities: &'a EffectiveVisibilities,
836}
837
838impl<'a, 'tcx> TestReachabilityVisitor<'a, 'tcx> {
839 fn effective_visibility_diagnostic(&mut self, def_id: LocalDefId) {
840 if self.tcx.has_attr(def_id, sym::rustc_effective_visibility) {
841 let mut error_msg = String::new();
842 let span = self.tcx.def_span(def_id.to_def_id());
843 if let Some(effective_vis) = self.effective_visibilities.effective_vis(def_id) {
844 for level in Level::all_levels() {
845 let vis_str = effective_vis.at_level(level).to_string(def_id, self.tcx);
846 if level != Level::Direct {
847 error_msg.push_str(", ");
848 }
849 error_msg.push_str(&format!("{level:?}: {vis_str}"));
850 }
851 } else {
852 error_msg.push_str("not in the table");
853 }
854 self.tcx.dcx().emit_err(ReportEffectiveVisibility { span, descr: error_msg });
855 }
856 }
857}
858
859impl<'a, 'tcx> Visitor<'tcx> for TestReachabilityVisitor<'a, 'tcx> {
860 fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
861 self.effective_visibility_diagnostic(item.owner_id.def_id);
862
863 match item.kind {
864 hir::ItemKind::Enum(ref def, _) => {
865 for variant in def.variants.iter() {
866 self.effective_visibility_diagnostic(variant.def_id);
867 if let Some(ctor_def_id) = variant.data.ctor_def_id() {
868 self.effective_visibility_diagnostic(ctor_def_id);
869 }
870 for field in variant.data.fields() {
871 self.effective_visibility_diagnostic(field.def_id);
872 }
873 }
874 }
875 hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => {
876 if let Some(ctor_def_id) = def.ctor_def_id() {
877 self.effective_visibility_diagnostic(ctor_def_id);
878 }
879 for field in def.fields() {
880 self.effective_visibility_diagnostic(field.def_id);
881 }
882 }
883 _ => {}
884 }
885 }
886
887 fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem<'tcx>) {
888 self.effective_visibility_diagnostic(item.owner_id.def_id);
889 }
890 fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem<'tcx>) {
891 self.effective_visibility_diagnostic(item.owner_id.def_id);
892 }
893 fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
894 self.effective_visibility_diagnostic(item.owner_id.def_id);
895 }
896}
897
898struct NamePrivacyVisitor<'tcx> {
906 tcx: TyCtxt<'tcx>,
907 maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
908}
909
910impl<'tcx> NamePrivacyVisitor<'tcx> {
911 #[track_caller]
915 fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> {
916 self.maybe_typeck_results
917 .expect("`NamePrivacyVisitor::typeck_results` called outside of body")
918 }
919
920 fn check_field(
922 &mut self,
923 hir_id: hir::HirId, use_ctxt: Span, def: ty::AdtDef<'tcx>, field: &'tcx ty::FieldDef,
927 ) -> bool {
928 if def.is_enum() {
929 return true;
930 }
931
932 let ident = Ident::new(kw::Empty, use_ctxt);
934 let def_id = self.tcx.adjust_ident_and_get_scope(ident, def.did(), hir_id).1;
935 !field.vis.is_accessible_from(def_id, self.tcx)
936 }
937
938 fn emit_unreachable_field_error(
940 &mut self,
941 fields: Vec<(Symbol, Span, bool )>,
942 def: ty::AdtDef<'tcx>, update_syntax: Option<Span>,
944 struct_span: Span,
945 ) {
946 if def.is_enum() || fields.is_empty() {
947 return;
948 }
949
950 let Some(field_names) = listify(&fields[..], |(n, _, _)| format!("`{n}`")) else { return };
962 let span: MultiSpan = fields.iter().map(|(_, span, _)| *span).collect::<Vec<Span>>().into();
963
964 let rest_field_names: Vec<_> =
966 fields.iter().filter(|(_, _, is_present)| !is_present).map(|(n, _, _)| n).collect();
967 let rest_len = rest_field_names.len();
968 let rest_field_names =
969 listify(&rest_field_names[..], |n| format!("`{n}`")).unwrap_or_default();
970 let labels = fields
972 .iter()
973 .filter(|(_, _, is_present)| *is_present)
974 .map(|(_, span, _)| FieldIsPrivateLabel::Other { span: *span })
975 .chain(update_syntax.iter().map(|span| FieldIsPrivateLabel::IsUpdateSyntax {
976 span: *span,
977 rest_field_names: rest_field_names.clone(),
978 rest_len,
979 }))
980 .collect();
981
982 self.tcx.dcx().emit_err(FieldIsPrivate {
983 span,
984 struct_span: if self
985 .tcx
986 .sess
987 .source_map()
988 .is_multiline(fields[0].1.between(struct_span))
989 {
990 Some(struct_span)
991 } else {
992 None
993 },
994 field_names,
995 variant_descr: def.variant_descr(),
996 def_path_str: self.tcx.def_path_str(def.did()),
997 labels,
998 len: fields.len(),
999 });
1000 }
1001
1002 fn check_expanded_fields(
1003 &mut self,
1004 adt: ty::AdtDef<'tcx>,
1005 variant: &'tcx ty::VariantDef,
1006 fields: &[hir::ExprField<'tcx>],
1007 hir_id: hir::HirId,
1008 span: Span,
1009 struct_span: Span,
1010 ) {
1011 let mut failed_fields = vec![];
1012 for (vf_index, variant_field) in variant.fields.iter_enumerated() {
1013 let field =
1014 fields.iter().find(|f| self.typeck_results().field_index(f.hir_id) == vf_index);
1015 let (hir_id, use_ctxt, span) = match field {
1016 Some(field) => (field.hir_id, field.ident.span, field.span),
1017 None => (hir_id, span, span),
1018 };
1019 if self.check_field(hir_id, use_ctxt, adt, variant_field) {
1020 let name = match field {
1021 Some(field) => field.ident.name,
1022 None => variant_field.name,
1023 };
1024 failed_fields.push((name, span, field.is_some()));
1025 }
1026 }
1027 self.emit_unreachable_field_error(failed_fields, adt, Some(span), struct_span);
1028 }
1029}
1030
1031impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> {
1032 fn visit_nested_body(&mut self, body_id: hir::BodyId) {
1033 let new_typeck_results = self.tcx.typeck_body(body_id);
1034 if new_typeck_results.tainted_by_errors.is_some() {
1036 return;
1037 }
1038 let old_maybe_typeck_results = self.maybe_typeck_results.replace(new_typeck_results);
1039 self.visit_body(self.tcx.hir().body(body_id));
1040 self.maybe_typeck_results = old_maybe_typeck_results;
1041 }
1042
1043 fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
1044 if let hir::ExprKind::Struct(qpath, fields, ref base) = expr.kind {
1045 let res = self.typeck_results().qpath_res(qpath, expr.hir_id);
1046 let adt = self.typeck_results().expr_ty(expr).ty_adt_def().unwrap();
1047 let variant = adt.variant_of_res(res);
1048 match *base {
1049 hir::StructTailExpr::Base(base) => {
1050 self.check_expanded_fields(
1054 adt,
1055 variant,
1056 fields,
1057 base.hir_id,
1058 base.span,
1059 qpath.span(),
1060 );
1061 }
1062 hir::StructTailExpr::DefaultFields(span) => {
1063 self.check_expanded_fields(
1064 adt,
1065 variant,
1066 fields,
1067 expr.hir_id,
1068 span,
1069 qpath.span(),
1070 );
1071 }
1072 hir::StructTailExpr::None => {
1073 let mut failed_fields = vec![];
1074 for field in fields {
1075 let (hir_id, use_ctxt) = (field.hir_id, field.ident.span);
1076 let index = self.typeck_results().field_index(field.hir_id);
1077 if self.check_field(hir_id, use_ctxt, adt, &variant.fields[index]) {
1078 failed_fields.push((field.ident.name, field.ident.span, true));
1079 }
1080 }
1081 self.emit_unreachable_field_error(failed_fields, adt, None, qpath.span());
1082 }
1083 }
1084 }
1085
1086 intravisit::walk_expr(self, expr);
1087 }
1088
1089 fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) {
1090 if let PatKind::Struct(ref qpath, fields, _) = pat.kind {
1091 let res = self.typeck_results().qpath_res(qpath, pat.hir_id);
1092 let adt = self.typeck_results().pat_ty(pat).ty_adt_def().unwrap();
1093 let variant = adt.variant_of_res(res);
1094 let mut failed_fields = vec![];
1095 for field in fields {
1096 let (hir_id, use_ctxt) = (field.hir_id, field.ident.span);
1097 let index = self.typeck_results().field_index(field.hir_id);
1098 if self.check_field(hir_id, use_ctxt, adt, &variant.fields[index]) {
1099 failed_fields.push((field.ident.name, field.ident.span, true));
1100 }
1101 }
1102 self.emit_unreachable_field_error(failed_fields, adt, None, qpath.span());
1103 }
1104
1105 intravisit::walk_pat(self, pat);
1106 }
1107}
1108
1109struct TypePrivacyVisitor<'tcx> {
1116 tcx: TyCtxt<'tcx>,
1117 module_def_id: LocalModDefId,
1118 maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
1119 span: Span,
1120}
1121
1122impl<'tcx> TypePrivacyVisitor<'tcx> {
1123 fn item_is_accessible(&self, did: DefId) -> bool {
1124 self.tcx.visibility(did).is_accessible_from(self.module_def_id, self.tcx)
1125 }
1126
1127 fn check_expr_pat_type(&mut self, id: hir::HirId, span: Span) -> bool {
1129 self.span = span;
1130 let typeck_results = self
1131 .maybe_typeck_results
1132 .unwrap_or_else(|| span_bug!(span, "`hir::Expr` or `hir::Pat` outside of a body"));
1133 let result: ControlFlow<()> = try {
1134 self.visit(typeck_results.node_type(id))?;
1135 self.visit(typeck_results.node_args(id))?;
1136 if let Some(adjustments) = typeck_results.adjustments().get(id) {
1137 adjustments.iter().try_for_each(|adjustment| self.visit(adjustment.target))?;
1138 }
1139 };
1140 result.is_break()
1141 }
1142
1143 fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
1144 let is_error = !self.item_is_accessible(def_id);
1145 if is_error {
1146 self.tcx.dcx().emit_err(ItemIsPrivate { span: self.span, kind, descr: descr.into() });
1147 }
1148 is_error
1149 }
1150}
1151
1152impl<'tcx> rustc_ty_utils::sig_types::SpannedTypeVisitor<'tcx> for TypePrivacyVisitor<'tcx> {
1153 type Result = ControlFlow<()>;
1154 fn visit(&mut self, span: Span, value: impl TypeVisitable<TyCtxt<'tcx>>) -> Self::Result {
1155 self.span = span;
1156 value.visit_with(&mut self.skeleton())
1157 }
1158}
1159
1160impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
1161 fn visit_nested_body(&mut self, body_id: hir::BodyId) {
1162 let old_maybe_typeck_results =
1163 self.maybe_typeck_results.replace(self.tcx.typeck_body(body_id));
1164 self.visit_body(self.tcx.hir().body(body_id));
1165 self.maybe_typeck_results = old_maybe_typeck_results;
1166 }
1167
1168 fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
1169 self.span = hir_ty.span;
1170 if self
1171 .visit(
1172 self.maybe_typeck_results
1173 .unwrap_or_else(|| span_bug!(hir_ty.span, "`hir::Ty` outside of a body"))
1174 .node_type(hir_ty.hir_id),
1175 )
1176 .is_break()
1177 {
1178 return;
1179 }
1180
1181 intravisit::walk_ty(self, hir_ty);
1182 }
1183
1184 fn visit_infer(
1185 &mut self,
1186 inf_id: rustc_hir::HirId,
1187 inf_span: Span,
1188 _kind: InferKind<'tcx>,
1189 ) -> Self::Result {
1190 self.span = inf_span;
1191 if let Some(ty) = self
1192 .maybe_typeck_results
1193 .unwrap_or_else(|| span_bug!(inf_span, "Inference variable outside of a body"))
1194 .node_type_opt(inf_id)
1195 {
1196 if self.visit(ty).is_break() {
1197 return;
1198 }
1199 } else {
1200 }
1202
1203 self.visit_id(inf_id)
1204 }
1205
1206 fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
1208 if self.check_expr_pat_type(expr.hir_id, expr.span) {
1209 return;
1211 }
1212 match expr.kind {
1213 hir::ExprKind::Assign(_, rhs, _) | hir::ExprKind::Match(rhs, ..) => {
1214 if self.check_expr_pat_type(rhs.hir_id, rhs.span) {
1216 return;
1217 }
1218 }
1219 hir::ExprKind::MethodCall(segment, ..) => {
1220 self.span = segment.ident.span;
1222 let typeck_results = self
1223 .maybe_typeck_results
1224 .unwrap_or_else(|| span_bug!(self.span, "`hir::Expr` outside of a body"));
1225 if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) {
1226 if self.visit(self.tcx.type_of(def_id).instantiate_identity()).is_break() {
1227 return;
1228 }
1229 } else {
1230 self.tcx
1231 .dcx()
1232 .span_delayed_bug(expr.span, "no type-dependent def for method call");
1233 }
1234 }
1235 _ => {}
1236 }
1237
1238 intravisit::walk_expr(self, expr);
1239 }
1240
1241 fn visit_qpath(&mut self, qpath: &'tcx hir::QPath<'tcx>, id: hir::HirId, span: Span) {
1248 let def = match qpath {
1249 hir::QPath::Resolved(_, path) => match path.res {
1250 Res::Def(kind, def_id) => Some((kind, def_id)),
1251 _ => None,
1252 },
1253 hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => {
1254 match self.maybe_typeck_results {
1255 Some(typeck_results) => typeck_results.type_dependent_def(id),
1256 None => None,
1258 }
1259 }
1260 };
1261 let def = def.filter(|(kind, _)| {
1262 matches!(
1263 kind,
1264 DefKind::AssocFn | DefKind::AssocConst | DefKind::AssocTy | DefKind::Static { .. }
1265 )
1266 });
1267 if let Some((kind, def_id)) = def {
1268 let is_local_static =
1269 if let DefKind::Static { .. } = kind { def_id.is_local() } else { false };
1270 if !self.item_is_accessible(def_id) && !is_local_static {
1271 let name = match *qpath {
1272 hir::QPath::LangItem(it, ..) => {
1273 self.tcx.lang_items().get(it).map(|did| self.tcx.def_path_str(did))
1274 }
1275 hir::QPath::Resolved(_, path) => Some(self.tcx.def_path_str(path.res.def_id())),
1276 hir::QPath::TypeRelative(_, segment) => Some(segment.ident.to_string()),
1277 };
1278 let kind = self.tcx.def_descr(def_id);
1279 let sess = self.tcx.sess;
1280 let _ = match name {
1281 Some(name) => {
1282 sess.dcx().emit_err(ItemIsPrivate { span, kind, descr: (&name).into() })
1283 }
1284 None => sess.dcx().emit_err(UnnamedItemIsPrivate { span, kind }),
1285 };
1286 return;
1287 }
1288 }
1289
1290 intravisit::walk_qpath(self, qpath, id);
1291 }
1292
1293 fn visit_pat(&mut self, pattern: &'tcx hir::Pat<'tcx>) {
1295 if self.check_expr_pat_type(pattern.hir_id, pattern.span) {
1296 return;
1298 }
1299
1300 intravisit::walk_pat(self, pattern);
1301 }
1302
1303 fn visit_local(&mut self, local: &'tcx hir::LetStmt<'tcx>) {
1304 if let Some(init) = local.init {
1305 if self.check_expr_pat_type(init.hir_id, init.span) {
1306 return;
1308 }
1309 }
1310
1311 intravisit::walk_local(self, local);
1312 }
1313}
1314
1315impl<'tcx> DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> {
1316 type Result = ControlFlow<()>;
1317 fn tcx(&self) -> TyCtxt<'tcx> {
1318 self.tcx
1319 }
1320 fn visit_def_id(
1321 &mut self,
1322 def_id: DefId,
1323 kind: &str,
1324 descr: &dyn fmt::Display,
1325 ) -> Self::Result {
1326 if self.check_def_id(def_id, kind, descr) {
1327 ControlFlow::Break(())
1328 } else {
1329 ControlFlow::Continue(())
1330 }
1331 }
1332}
1333
1334struct SearchInterfaceForPrivateItemsVisitor<'tcx> {
1342 tcx: TyCtxt<'tcx>,
1343 item_def_id: LocalDefId,
1344 required_visibility: ty::Visibility,
1346 required_effective_vis: Option<EffectiveVisibility>,
1347 in_assoc_ty: bool,
1348 in_primary_interface: bool,
1349}
1350
1351impl SearchInterfaceForPrivateItemsVisitor<'_> {
1352 fn generics(&mut self) -> &mut Self {
1353 self.in_primary_interface = true;
1354 for param in &self.tcx.generics_of(self.item_def_id).own_params {
1355 match param.kind {
1356 GenericParamDefKind::Lifetime => {}
1357 GenericParamDefKind::Type { has_default, .. } => {
1358 if has_default {
1359 self.visit(self.tcx.type_of(param.def_id).instantiate_identity());
1360 }
1361 }
1362 GenericParamDefKind::Const { .. } => {
1364 self.visit(self.tcx.type_of(param.def_id).instantiate_identity());
1365 }
1366 }
1367 }
1368 self
1369 }
1370
1371 fn predicates(&mut self) -> &mut Self {
1372 self.in_primary_interface = false;
1373 self.visit_predicates(self.tcx.explicit_predicates_of(self.item_def_id));
1380 self
1381 }
1382
1383 fn bounds(&mut self) -> &mut Self {
1384 self.in_primary_interface = false;
1385 self.visit_clauses(self.tcx.explicit_item_bounds(self.item_def_id).skip_binder());
1386 self
1387 }
1388
1389 fn ty(&mut self) -> &mut Self {
1390 self.in_primary_interface = true;
1391 self.visit(self.tcx.type_of(self.item_def_id).instantiate_identity());
1392 self
1393 }
1394
1395 fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
1396 if self.leaks_private_dep(def_id) {
1397 self.tcx.emit_node_span_lint(
1398 lint::builtin::EXPORTED_PRIVATE_DEPENDENCIES,
1399 self.tcx.local_def_id_to_hir_id(self.item_def_id),
1400 self.tcx.def_span(self.item_def_id.to_def_id()),
1401 FromPrivateDependencyInPublicInterface {
1402 kind,
1403 descr: descr.into(),
1404 krate: self.tcx.crate_name(def_id.krate),
1405 },
1406 );
1407 }
1408
1409 let Some(local_def_id) = def_id.as_local() else {
1410 return false;
1411 };
1412
1413 let vis = self.tcx.local_visibility(local_def_id);
1414 let span = self.tcx.def_span(self.item_def_id.to_def_id());
1415 let vis_span = self.tcx.def_span(def_id);
1416 if self.in_assoc_ty && !vis.is_at_least(self.required_visibility, self.tcx) {
1417 let vis_descr = match vis {
1418 ty::Visibility::Public => "public",
1419 ty::Visibility::Restricted(vis_def_id) => {
1420 if vis_def_id
1421 == self.tcx.parent_module_from_def_id(local_def_id).to_local_def_id()
1422 {
1423 "private"
1424 } else if vis_def_id.is_top_level_module() {
1425 "crate-private"
1426 } else {
1427 "restricted"
1428 }
1429 }
1430 };
1431
1432 self.tcx.dcx().emit_err(InPublicInterface {
1433 span,
1434 vis_descr,
1435 kind,
1436 descr: descr.into(),
1437 vis_span,
1438 });
1439 return false;
1440 }
1441
1442 let Some(effective_vis) = self.required_effective_vis else {
1443 return false;
1444 };
1445
1446 let reachable_at_vis = *effective_vis.at_level(Level::Reachable);
1447
1448 if !vis.is_at_least(reachable_at_vis, self.tcx) {
1449 let lint = if self.in_primary_interface {
1450 lint::builtin::PRIVATE_INTERFACES
1451 } else {
1452 lint::builtin::PRIVATE_BOUNDS
1453 };
1454 self.tcx.emit_node_span_lint(
1455 lint,
1456 self.tcx.local_def_id_to_hir_id(self.item_def_id),
1457 span,
1458 PrivateInterfacesOrBoundsLint {
1459 item_span: span,
1460 item_kind: self.tcx.def_descr(self.item_def_id.to_def_id()),
1461 item_descr: (&LazyDefPathStr {
1462 def_id: self.item_def_id.to_def_id(),
1463 tcx: self.tcx,
1464 })
1465 .into(),
1466 item_vis_descr: &reachable_at_vis.to_string(self.item_def_id, self.tcx),
1467 ty_span: vis_span,
1468 ty_kind: kind,
1469 ty_descr: descr.into(),
1470 ty_vis_descr: &vis.to_string(local_def_id, self.tcx),
1471 },
1472 );
1473 }
1474
1475 false
1476 }
1477
1478 fn leaks_private_dep(&self, item_id: DefId) -> bool {
1483 let ret = self.required_visibility.is_public() && self.tcx.is_private_dep(item_id.krate);
1484
1485 debug!("leaks_private_dep(item_id={:?})={}", item_id, ret);
1486 ret
1487 }
1488}
1489
1490impl<'tcx> DefIdVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'tcx> {
1491 type Result = ControlFlow<()>;
1492 fn tcx(&self) -> TyCtxt<'tcx> {
1493 self.tcx
1494 }
1495 fn visit_def_id(
1496 &mut self,
1497 def_id: DefId,
1498 kind: &str,
1499 descr: &dyn fmt::Display,
1500 ) -> Self::Result {
1501 if self.check_def_id(def_id, kind, descr) {
1502 ControlFlow::Break(())
1503 } else {
1504 ControlFlow::Continue(())
1505 }
1506 }
1507}
1508
1509struct PrivateItemsInPublicInterfacesChecker<'a, 'tcx> {
1510 tcx: TyCtxt<'tcx>,
1511 effective_visibilities: &'a EffectiveVisibilities,
1512}
1513
1514impl<'tcx> PrivateItemsInPublicInterfacesChecker<'_, 'tcx> {
1515 fn check(
1516 &self,
1517 def_id: LocalDefId,
1518 required_visibility: ty::Visibility,
1519 required_effective_vis: Option<EffectiveVisibility>,
1520 ) -> SearchInterfaceForPrivateItemsVisitor<'tcx> {
1521 SearchInterfaceForPrivateItemsVisitor {
1522 tcx: self.tcx,
1523 item_def_id: def_id,
1524 required_visibility,
1525 required_effective_vis,
1526 in_assoc_ty: false,
1527 in_primary_interface: true,
1528 }
1529 }
1530
1531 fn check_unnameable(&self, def_id: LocalDefId, effective_vis: Option<EffectiveVisibility>) {
1532 let Some(effective_vis) = effective_vis else {
1533 return;
1534 };
1535
1536 let reexported_at_vis = effective_vis.at_level(Level::Reexported);
1537 let reachable_at_vis = effective_vis.at_level(Level::Reachable);
1538
1539 if reachable_at_vis.is_public() && reexported_at_vis != reachable_at_vis {
1540 let hir_id = self.tcx.local_def_id_to_hir_id(def_id);
1541 let span = self.tcx.def_span(def_id.to_def_id());
1542 self.tcx.emit_node_span_lint(
1543 lint::builtin::UNNAMEABLE_TYPES,
1544 hir_id,
1545 span,
1546 UnnameableTypesLint {
1547 span,
1548 kind: self.tcx.def_descr(def_id.to_def_id()),
1549 descr: (&LazyDefPathStr { def_id: def_id.to_def_id(), tcx: self.tcx }).into(),
1550 reachable_vis: &reachable_at_vis.to_string(def_id, self.tcx),
1551 reexported_vis: &reexported_at_vis.to_string(def_id, self.tcx),
1552 },
1553 );
1554 }
1555 }
1556
1557 fn check_assoc_item(
1558 &self,
1559 def_id: LocalDefId,
1560 assoc_item_kind: AssocItemKind,
1561 vis: ty::Visibility,
1562 effective_vis: Option<EffectiveVisibility>,
1563 ) {
1564 let mut check = self.check(def_id, vis, effective_vis);
1565
1566 let (check_ty, is_assoc_ty) = match assoc_item_kind {
1567 AssocItemKind::Const | AssocItemKind::Fn { .. } => (true, false),
1568 AssocItemKind::Type => (self.tcx.defaultness(def_id).has_value(), true),
1569 };
1570
1571 check.in_assoc_ty = is_assoc_ty;
1572 check.generics().predicates();
1573 if check_ty {
1574 check.ty();
1575 }
1576 }
1577
1578 fn get(&self, def_id: LocalDefId) -> Option<EffectiveVisibility> {
1579 self.effective_visibilities.effective_vis(def_id).copied()
1580 }
1581
1582 fn check_item(&mut self, id: ItemId) {
1583 let tcx = self.tcx;
1584 let def_id = id.owner_id.def_id;
1585 let item_visibility = tcx.local_visibility(def_id);
1586 let effective_vis = self.get(def_id);
1587 let def_kind = tcx.def_kind(def_id);
1588
1589 match def_kind {
1590 DefKind::Const | DefKind::Static { .. } | DefKind::Fn | DefKind::TyAlias => {
1591 if let DefKind::TyAlias = def_kind {
1592 self.check_unnameable(def_id, effective_vis);
1593 }
1594 self.check(def_id, item_visibility, effective_vis).generics().predicates().ty();
1595 }
1596 DefKind::OpaqueTy => {
1597 self.check(def_id, item_visibility, effective_vis).generics().bounds();
1600 }
1601 DefKind::Trait => {
1602 let item = tcx.hir().item(id);
1603 if let hir::ItemKind::Trait(.., trait_item_refs) = item.kind {
1604 self.check_unnameable(item.owner_id.def_id, effective_vis);
1605
1606 self.check(item.owner_id.def_id, item_visibility, effective_vis)
1607 .generics()
1608 .predicates();
1609
1610 for trait_item_ref in trait_item_refs {
1611 self.check_assoc_item(
1612 trait_item_ref.id.owner_id.def_id,
1613 trait_item_ref.kind,
1614 item_visibility,
1615 effective_vis,
1616 );
1617
1618 if let AssocItemKind::Type = trait_item_ref.kind {
1619 self.check(
1620 trait_item_ref.id.owner_id.def_id,
1621 item_visibility,
1622 effective_vis,
1623 )
1624 .bounds();
1625 }
1626 }
1627 }
1628 }
1629 DefKind::TraitAlias => {
1630 self.check(def_id, item_visibility, effective_vis).generics().predicates();
1631 }
1632 DefKind::Enum => {
1633 let item = tcx.hir().item(id);
1634 if let hir::ItemKind::Enum(ref def, _) = item.kind {
1635 self.check_unnameable(item.owner_id.def_id, effective_vis);
1636
1637 self.check(item.owner_id.def_id, item_visibility, effective_vis)
1638 .generics()
1639 .predicates();
1640
1641 for variant in def.variants {
1642 for field in variant.data.fields() {
1643 self.check(field.def_id, item_visibility, effective_vis).ty();
1644 }
1645 }
1646 }
1647 }
1648 DefKind::ForeignMod => {
1650 let item = tcx.hir().item(id);
1651 if let hir::ItemKind::ForeignMod { items, .. } = item.kind {
1652 for foreign_item in items {
1653 let foreign_item = tcx.hir().foreign_item(foreign_item.id);
1654
1655 let ev = self.get(foreign_item.owner_id.def_id);
1656 let vis = tcx.local_visibility(foreign_item.owner_id.def_id);
1657
1658 if let ForeignItemKind::Type = foreign_item.kind {
1659 self.check_unnameable(foreign_item.owner_id.def_id, ev);
1660 }
1661
1662 self.check(foreign_item.owner_id.def_id, vis, ev)
1663 .generics()
1664 .predicates()
1665 .ty();
1666 }
1667 }
1668 }
1669 DefKind::Struct | DefKind::Union => {
1671 let item = tcx.hir().item(id);
1672 if let hir::ItemKind::Struct(ref struct_def, _)
1673 | hir::ItemKind::Union(ref struct_def, _) = item.kind
1674 {
1675 self.check_unnameable(item.owner_id.def_id, effective_vis);
1676 self.check(item.owner_id.def_id, item_visibility, effective_vis)
1677 .generics()
1678 .predicates();
1679
1680 for field in struct_def.fields() {
1681 let field_visibility = tcx.local_visibility(field.def_id);
1682 let field_ev = self.get(field.def_id);
1683
1684 self.check(
1685 field.def_id,
1686 min(item_visibility, field_visibility, tcx),
1687 field_ev,
1688 )
1689 .ty();
1690 }
1691 }
1692 }
1693 DefKind::Impl { .. } => {
1698 let item = tcx.hir().item(id);
1699 if let hir::ItemKind::Impl(impl_) = item.kind {
1700 let impl_vis = ty::Visibility::of_impl::<false>(
1701 item.owner_id.def_id,
1702 tcx,
1703 &Default::default(),
1704 );
1705
1706 let impl_ev = EffectiveVisibility::of_impl::<false>(
1718 item.owner_id.def_id,
1719 tcx,
1720 self.effective_visibilities,
1721 );
1722
1723 if impl_.of_trait.is_none() {
1726 self.check(item.owner_id.def_id, impl_vis, Some(impl_ev))
1727 .generics()
1728 .predicates();
1729 }
1730 for impl_item_ref in impl_.items {
1731 let impl_item_vis = if impl_.of_trait.is_none() {
1732 min(
1733 tcx.local_visibility(impl_item_ref.id.owner_id.def_id),
1734 impl_vis,
1735 tcx,
1736 )
1737 } else {
1738 impl_vis
1739 };
1740
1741 let impl_item_ev = if impl_.of_trait.is_none() {
1742 self.get(impl_item_ref.id.owner_id.def_id)
1743 .map(|ev| ev.min(impl_ev, self.tcx))
1744 } else {
1745 Some(impl_ev)
1746 };
1747
1748 self.check_assoc_item(
1749 impl_item_ref.id.owner_id.def_id,
1750 impl_item_ref.kind,
1751 impl_item_vis,
1752 impl_item_ev,
1753 );
1754 }
1755 }
1756 }
1757 _ => {}
1758 }
1759 }
1760}
1761
1762pub fn provide(providers: &mut Providers) {
1763 *providers = Providers {
1764 effective_visibilities,
1765 check_private_in_public,
1766 check_mod_privacy,
1767 ..*providers
1768 };
1769}
1770
1771fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
1772 let mut visitor = NamePrivacyVisitor { tcx, maybe_typeck_results: None };
1774 tcx.hir().visit_item_likes_in_module(module_def_id, &mut visitor);
1775
1776 let span = tcx.def_span(module_def_id);
1779 let mut visitor = TypePrivacyVisitor { tcx, module_def_id, maybe_typeck_results: None, span };
1780
1781 let module = tcx.hir_module_items(module_def_id);
1782 for def_id in module.definitions() {
1783 rustc_ty_utils::sig_types::walk_types(tcx, def_id, &mut visitor);
1784
1785 if let Some(body_id) = tcx.hir().maybe_body_owned_by(def_id) {
1786 visitor.visit_nested_body(body_id.id());
1787 }
1788 }
1789
1790 for id in module.free_items() {
1791 if let ItemKind::Impl(i) = tcx.hir().item(id).kind {
1792 if let Some(item) = i.of_trait {
1793 let trait_ref = tcx.impl_trait_ref(id.owner_id.def_id).unwrap();
1794 let trait_ref = trait_ref.instantiate_identity();
1795 visitor.span = item.path.span;
1796 visitor.visit_def_id(trait_ref.def_id, "trait", &trait_ref.print_only_trait_path());
1797 }
1798 }
1799 }
1800}
1801
1802fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities {
1803 let mut visitor = EmbargoVisitor {
1806 tcx,
1807 effective_visibilities: tcx.resolutions(()).effective_visibilities.clone(),
1808 macro_reachable: Default::default(),
1809 changed: false,
1810 };
1811
1812 visitor.effective_visibilities.check_invariants(tcx);
1813
1814 let impl_trait_pass = !tcx.sess.opts.actually_rustdoc;
1818 if impl_trait_pass {
1819 let krate = tcx.hir_crate_items(());
1822 for id in krate.opaques() {
1823 let opaque = tcx.hir_node_by_def_id(id).expect_opaque_ty();
1824 let should_visit = match opaque.origin {
1825 hir::OpaqueTyOrigin::FnReturn {
1826 parent,
1827 in_trait_or_impl: Some(hir::RpitContext::Trait),
1828 }
1829 | hir::OpaqueTyOrigin::AsyncFn {
1830 parent,
1831 in_trait_or_impl: Some(hir::RpitContext::Trait),
1832 } => match tcx.hir_node_by_def_id(parent).expect_trait_item().expect_fn().1 {
1833 hir::TraitFn::Required(_) => false,
1834 hir::TraitFn::Provided(..) => true,
1835 },
1836
1837 hir::OpaqueTyOrigin::FnReturn {
1840 in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
1841 ..
1842 }
1843 | hir::OpaqueTyOrigin::AsyncFn {
1844 in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
1845 ..
1846 }
1847 | hir::OpaqueTyOrigin::TyAlias { .. } => true,
1848 };
1849 if should_visit {
1850 let pub_ev = EffectiveVisibility::from_vis(ty::Visibility::Public);
1854 visitor
1855 .reach_through_impl_trait(opaque.def_id, pub_ev)
1856 .generics()
1857 .predicates()
1858 .ty();
1859 }
1860 }
1861
1862 visitor.changed = false;
1863 }
1864
1865 loop {
1866 tcx.hir().visit_all_item_likes_in_crate(&mut visitor);
1867 if visitor.changed {
1868 visitor.changed = false;
1869 } else {
1870 break;
1871 }
1872 }
1873 visitor.effective_visibilities.check_invariants(tcx);
1874
1875 let mut check_visitor =
1876 TestReachabilityVisitor { tcx, effective_visibilities: &visitor.effective_visibilities };
1877 check_visitor.effective_visibility_diagnostic(CRATE_DEF_ID);
1878 tcx.hir().visit_all_item_likes_in_crate(&mut check_visitor);
1879
1880 tcx.arena.alloc(visitor.effective_visibilities)
1881}
1882
1883fn check_private_in_public(tcx: TyCtxt<'_>, (): ()) {
1884 let effective_visibilities = tcx.effective_visibilities(());
1885 let mut checker = PrivateItemsInPublicInterfacesChecker { tcx, effective_visibilities };
1887
1888 for id in tcx.hir().items() {
1889 checker.check_item(id);
1890 }
1891}