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