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