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