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