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