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, 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 ty::ClauseKind::UnstableFeature(_) => V::Result::output(),
160 }
161 }
162
163 fn visit_clauses(&mut self, clauses: &[(ty::Clause<'tcx>, Span)]) -> V::Result {
164 for &(clause, _) in clauses {
165 try_visit!(self.visit_clause(clause));
166 }
167 V::Result::output()
168 }
169}
170
171impl<'tcx, V> TypeVisitor<TyCtxt<'tcx>> for DefIdVisitorSkeleton<'_, 'tcx, V>
172where
173 V: DefIdVisitor<'tcx> + ?Sized,
174{
175 type Result = V::Result;
176
177 fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> Self::Result {
178 self.visit_clause(p.as_clause().unwrap())
179 }
180
181 fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
182 let tcx = self.def_id_visitor.tcx();
183 match *ty.kind() {
186 ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), ..)
187 | ty::Foreign(def_id)
188 | ty::FnDef(def_id, ..)
189 | ty::Closure(def_id, ..)
190 | ty::CoroutineClosure(def_id, ..)
191 | ty::Coroutine(def_id, ..) => {
192 try_visit!(self.def_id_visitor.visit_def_id(def_id, "type", &ty));
193 if V::SHALLOW {
194 return V::Result::output();
195 }
196 if let ty::FnDef(..) = ty.kind() {
200 try_visit!(tcx.fn_sig(def_id).instantiate_identity().visit_with(self));
202 }
203 if let Some(assoc_item) = tcx.opt_associated_item(def_id) {
208 if let Some(impl_def_id) = assoc_item.impl_container(tcx) {
209 try_visit!(
210 tcx.type_of(impl_def_id).instantiate_identity().visit_with(self)
211 );
212 }
213 }
214 }
215 ty::Alias(kind @ (ty::Inherent | ty::Free | ty::Projection), data) => {
216 if self.def_id_visitor.skip_assoc_tys() {
217 return V::Result::output();
223 }
224
225 try_visit!(self.def_id_visitor.visit_def_id(
226 data.def_id,
227 match kind {
228 ty::Inherent | ty::Projection => "associated type",
229 ty::Free => "type alias",
230 ty::Opaque => unreachable!(),
231 },
232 &LazyDefPathStr { def_id: data.def_id, tcx },
233 ));
234
235 return if V::SHALLOW {
237 V::Result::output()
238 } else if kind == ty::Projection {
239 self.visit_projection_term(data.into())
240 } else {
241 V::Result::from_branch(
242 data.args.iter().try_for_each(|arg| arg.visit_with(self).branch()),
243 )
244 };
245 }
246 ty::Dynamic(predicates, ..) => {
247 for predicate in predicates {
250 let trait_ref = match predicate.skip_binder() {
251 ty::ExistentialPredicate::Trait(trait_ref) => trait_ref,
252 ty::ExistentialPredicate::Projection(proj) => proj.trait_ref(tcx),
253 ty::ExistentialPredicate::AutoTrait(def_id) => {
254 ty::ExistentialTraitRef::new(tcx, def_id, ty::GenericArgs::empty())
255 }
256 };
257 let ty::ExistentialTraitRef { def_id, .. } = trait_ref;
258 try_visit!(self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref));
259 }
260 }
261 ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
262 if self.visited_opaque_tys.insert(def_id) {
264 try_visit!(self.visit_clauses(tcx.explicit_item_bounds(def_id).skip_binder()));
272 }
273 }
274 ty::Bool
277 | ty::Char
278 | ty::Int(..)
279 | ty::Uint(..)
280 | ty::Float(..)
281 | ty::Str
282 | ty::Never
283 | ty::Array(..)
284 | ty::Slice(..)
285 | ty::Tuple(..)
286 | ty::RawPtr(..)
287 | ty::Ref(..)
288 | ty::Pat(..)
289 | ty::FnPtr(..)
290 | ty::UnsafeBinder(_)
291 | ty::Param(..)
292 | ty::Bound(..)
293 | ty::Error(_)
294 | ty::CoroutineWitness(..) => {}
295 ty::Placeholder(..) | ty::Infer(..) => {
296 bug!("unexpected type: {:?}", ty)
297 }
298 }
299
300 if V::SHALLOW { V::Result::output() } else { ty.super_visit_with(self) }
301 }
302
303 fn visit_const(&mut self, c: Const<'tcx>) -> Self::Result {
304 let tcx = self.def_id_visitor.tcx();
305 tcx.expand_abstract_consts(c).super_visit_with(self)
306 }
307}
308
309fn min(vis1: ty::Visibility, vis2: ty::Visibility, tcx: TyCtxt<'_>) -> ty::Visibility {
310 if vis1.is_at_least(vis2, tcx) { vis2 } else { vis1 }
311}
312
313struct FindMin<'a, 'tcx, VL: VisibilityLike, const SHALLOW: bool> {
318 tcx: TyCtxt<'tcx>,
319 effective_visibilities: &'a EffectiveVisibilities,
320 min: VL,
321}
322
323impl<'a, 'tcx, VL: VisibilityLike, const SHALLOW: bool> DefIdVisitor<'tcx>
324 for FindMin<'a, 'tcx, VL, SHALLOW>
325{
326 const SHALLOW: bool = SHALLOW;
327 fn skip_assoc_tys(&self) -> bool {
328 true
329 }
330 fn tcx(&self) -> TyCtxt<'tcx> {
331 self.tcx
332 }
333 fn visit_def_id(&mut self, def_id: DefId, _kind: &str, _descr: &dyn fmt::Display) {
334 if let Some(def_id) = def_id.as_local() {
335 self.min = VL::new_min(self, def_id);
336 }
337 }
338}
339
340trait VisibilityLike: Sized {
341 const MAX: Self;
342 fn new_min<const SHALLOW: bool>(
343 find: &FindMin<'_, '_, Self, SHALLOW>,
344 def_id: LocalDefId,
345 ) -> Self;
346
347 fn of_impl<const SHALLOW: bool>(
350 def_id: LocalDefId,
351 tcx: TyCtxt<'_>,
352 effective_visibilities: &EffectiveVisibilities,
353 ) -> Self {
354 let mut find = FindMin::<_, SHALLOW> { tcx, effective_visibilities, min: Self::MAX };
355 find.visit(tcx.type_of(def_id).instantiate_identity());
356 if let Some(trait_ref) = tcx.impl_trait_ref(def_id) {
357 find.visit_trait(trait_ref.instantiate_identity());
358 }
359 find.min
360 }
361}
362
363impl VisibilityLike for ty::Visibility {
364 const MAX: Self = ty::Visibility::Public;
365 fn new_min<const SHALLOW: bool>(
366 find: &FindMin<'_, '_, Self, SHALLOW>,
367 def_id: LocalDefId,
368 ) -> Self {
369 min(find.tcx.local_visibility(def_id), find.min, find.tcx)
370 }
371}
372
373impl VisibilityLike for EffectiveVisibility {
374 const MAX: Self = EffectiveVisibility::from_vis(ty::Visibility::Public);
375 fn new_min<const SHALLOW: bool>(
376 find: &FindMin<'_, '_, Self, SHALLOW>,
377 def_id: LocalDefId,
378 ) -> Self {
379 let effective_vis =
380 find.effective_visibilities.effective_vis(def_id).copied().unwrap_or_else(|| {
381 let private_vis = ty::Visibility::Restricted(
382 find.tcx.parent_module_from_def_id(def_id).to_local_def_id(),
383 );
384 EffectiveVisibility::from_vis(private_vis)
385 });
386
387 effective_vis.min(find.min, find.tcx)
388 }
389}
390
391struct EmbargoVisitor<'tcx> {
396 tcx: TyCtxt<'tcx>,
397
398 effective_visibilities: EffectiveVisibilities,
400 macro_reachable: FxHashSet<(LocalModDefId, LocalModDefId)>,
413 changed: bool,
415}
416
417struct ReachEverythingInTheInterfaceVisitor<'a, 'tcx> {
418 effective_vis: EffectiveVisibility,
419 item_def_id: LocalDefId,
420 ev: &'a mut EmbargoVisitor<'tcx>,
421 level: Level,
422}
423
424impl<'tcx> EmbargoVisitor<'tcx> {
425 fn get(&self, def_id: LocalDefId) -> Option<EffectiveVisibility> {
426 self.effective_visibilities.effective_vis(def_id).copied()
427 }
428
429 fn update(
431 &mut self,
432 def_id: LocalDefId,
433 inherited_effective_vis: EffectiveVisibility,
434 level: Level,
435 ) {
436 let nominal_vis = self.tcx.local_visibility(def_id);
437 self.update_eff_vis(def_id, inherited_effective_vis, Some(nominal_vis), level);
438 }
439
440 fn update_eff_vis(
441 &mut self,
442 def_id: LocalDefId,
443 inherited_effective_vis: EffectiveVisibility,
444 max_vis: Option<ty::Visibility>,
445 level: Level,
446 ) {
447 let private_vis =
449 ty::Visibility::Restricted(self.tcx.parent_module_from_def_id(def_id).into());
450 if max_vis != Some(private_vis) {
451 self.changed |= self.effective_visibilities.update(
452 def_id,
453 max_vis,
454 || private_vis,
455 inherited_effective_vis,
456 level,
457 self.tcx,
458 );
459 }
460 }
461
462 fn reach(
463 &mut self,
464 def_id: LocalDefId,
465 effective_vis: EffectiveVisibility,
466 ) -> ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
467 ReachEverythingInTheInterfaceVisitor {
468 effective_vis,
469 item_def_id: def_id,
470 ev: self,
471 level: Level::Reachable,
472 }
473 }
474
475 fn reach_through_impl_trait(
476 &mut self,
477 def_id: LocalDefId,
478 effective_vis: EffectiveVisibility,
479 ) -> ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
480 ReachEverythingInTheInterfaceVisitor {
481 effective_vis,
482 item_def_id: def_id,
483 ev: self,
484 level: Level::ReachableThroughImplTrait,
485 }
486 }
487
488 fn update_reachability_from_macro(
491 &mut self,
492 local_def_id: LocalDefId,
493 md: &MacroDef,
494 macro_ev: EffectiveVisibility,
495 ) {
496 let hir_id = self.tcx.local_def_id_to_hir_id(local_def_id);
498 let attrs = self.tcx.hir_attrs(hir_id);
499
500 if attrs::find_attr!(attrs, attrs::AttributeKind::MacroTransparency(x) => *x)
501 .unwrap_or(Transparency::fallback(md.macro_rules))
502 != Transparency::Opaque
503 {
504 return;
505 }
506
507 let macro_module_def_id = self.tcx.local_parent(local_def_id);
508 if self.tcx.def_kind(macro_module_def_id) != DefKind::Mod {
509 return;
511 }
512 let macro_module_def_id = LocalModDefId::new_unchecked(macro_module_def_id);
514
515 if self.effective_visibilities.public_at_level(local_def_id).is_none() {
516 return;
517 }
518
519 let mut module_def_id = macro_module_def_id;
522 loop {
523 let changed_reachability =
524 self.update_macro_reachable(module_def_id, macro_module_def_id, macro_ev);
525 if changed_reachability || module_def_id == LocalModDefId::CRATE_DEF_ID {
526 break;
527 }
528 module_def_id = LocalModDefId::new_unchecked(self.tcx.local_parent(module_def_id));
529 }
530 }
531
532 fn update_macro_reachable(
535 &mut self,
536 module_def_id: LocalModDefId,
537 defining_mod: LocalModDefId,
538 macro_ev: EffectiveVisibility,
539 ) -> bool {
540 if self.macro_reachable.insert((module_def_id, defining_mod)) {
541 for child in self.tcx.module_children_local(module_def_id.to_local_def_id()) {
542 if let Res::Def(def_kind, def_id) = child.res
543 && let Some(def_id) = def_id.as_local()
544 && child.vis.is_accessible_from(defining_mod, self.tcx)
545 {
546 let vis = self.tcx.local_visibility(def_id);
547 self.update_macro_reachable_def(def_id, def_kind, vis, defining_mod, macro_ev);
548 }
549 }
550 true
551 } else {
552 false
553 }
554 }
555
556 fn update_macro_reachable_def(
557 &mut self,
558 def_id: LocalDefId,
559 def_kind: DefKind,
560 vis: ty::Visibility,
561 module: LocalModDefId,
562 macro_ev: EffectiveVisibility,
563 ) {
564 self.update(def_id, macro_ev, Level::Reachable);
565 match def_kind {
566 DefKind::Const | DefKind::Static { .. } | DefKind::TraitAlias | DefKind::TyAlias => {
568 if vis.is_accessible_from(module, self.tcx) {
569 self.update(def_id, macro_ev, Level::Reachable);
570 }
571 }
572
573 DefKind::Macro(_) => {
578 let item = self.tcx.hir_expect_item(def_id);
579 if let hir::ItemKind::Macro(_, MacroDef { macro_rules: false, .. }, _) = item.kind {
580 if vis.is_accessible_from(module, self.tcx) {
581 self.update(def_id, macro_ev, Level::Reachable);
582 }
583 }
584 }
585
586 DefKind::Mod => {
591 if vis.is_accessible_from(module, self.tcx) {
592 self.update_macro_reachable(
593 LocalModDefId::new_unchecked(def_id),
594 module,
595 macro_ev,
596 );
597 }
598 }
599
600 DefKind::Struct | DefKind::Union => {
601 let item = self.tcx.hir_expect_item(def_id);
603 if let hir::ItemKind::Struct(_, _, ref struct_def)
604 | hir::ItemKind::Union(_, _, ref struct_def) = item.kind
605 {
606 for field in struct_def.fields() {
607 let field_vis = self.tcx.local_visibility(field.def_id);
608 if field_vis.is_accessible_from(module, self.tcx) {
609 self.reach(field.def_id, macro_ev).ty();
610 }
611 }
612 } else {
613 bug!("item {:?} with DefKind {:?}", item, def_kind);
614 }
615 }
616
617 DefKind::AssocConst
620 | DefKind::AssocTy
621 | DefKind::ConstParam
622 | DefKind::Ctor(_, _)
623 | DefKind::Enum
624 | DefKind::ForeignTy
625 | DefKind::Fn
626 | DefKind::OpaqueTy
627 | DefKind::AssocFn
628 | DefKind::Trait
629 | DefKind::TyParam
630 | DefKind::Variant
631 | DefKind::LifetimeParam
632 | DefKind::ExternCrate
633 | DefKind::Use
634 | DefKind::ForeignMod
635 | DefKind::AnonConst
636 | DefKind::InlineConst
637 | DefKind::Field
638 | DefKind::GlobalAsm
639 | DefKind::Impl { .. }
640 | DefKind::Closure
641 | DefKind::SyntheticCoroutineBody => (),
642 }
643 }
644}
645
646impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
647 fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
648 let item_ev = self.get(item.owner_id.def_id);
651 match item.kind {
652 hir::ItemKind::Use(..)
654 | hir::ItemKind::ExternCrate(..)
655 | hir::ItemKind::GlobalAsm { .. } => {}
656 hir::ItemKind::Mod(..) => {}
658 hir::ItemKind::Macro(_, macro_def, _) => {
659 if let Some(item_ev) = item_ev {
660 self.update_reachability_from_macro(item.owner_id.def_id, macro_def, item_ev);
661 }
662 }
663 hir::ItemKind::Const(..)
664 | hir::ItemKind::Static(..)
665 | hir::ItemKind::Fn { .. }
666 | hir::ItemKind::TyAlias(..) => {
667 if let Some(item_ev) = item_ev {
668 self.reach(item.owner_id.def_id, item_ev).generics().predicates().ty();
669 }
670 }
671 hir::ItemKind::Trait(.., trait_item_refs) => {
672 if let Some(item_ev) = item_ev {
673 self.reach(item.owner_id.def_id, item_ev).generics().predicates();
674
675 for trait_item_ref in trait_item_refs {
676 self.update(trait_item_ref.owner_id.def_id, item_ev, Level::Reachable);
677
678 let tcx = self.tcx;
679 let mut reach = self.reach(trait_item_ref.owner_id.def_id, item_ev);
680 reach.generics().predicates();
681
682 if let DefKind::AssocTy = tcx.def_kind(trait_item_ref.owner_id)
683 && !tcx.defaultness(trait_item_ref.owner_id).has_value()
684 {
685 } else {
687 reach.ty();
688 }
689 }
690 }
691 }
692 hir::ItemKind::TraitAlias(..) => {
693 if let Some(item_ev) = item_ev {
694 self.reach(item.owner_id.def_id, item_ev).generics().predicates();
695 }
696 }
697 hir::ItemKind::Impl(impl_) => {
698 let item_ev = EffectiveVisibility::of_impl::<true>(
709 item.owner_id.def_id,
710 self.tcx,
711 &self.effective_visibilities,
712 );
713
714 self.update_eff_vis(item.owner_id.def_id, item_ev, None, Level::Direct);
715
716 self.reach(item.owner_id.def_id, item_ev).generics().predicates().ty().trait_ref();
717
718 for impl_item_ref in impl_.items {
719 let def_id = impl_item_ref.owner_id.def_id;
720 let max_vis =
721 impl_.of_trait.is_none().then(|| self.tcx.local_visibility(def_id));
722 self.update_eff_vis(def_id, item_ev, max_vis, Level::Direct);
723
724 if let Some(impl_item_ev) = self.get(def_id) {
725 self.reach(def_id, impl_item_ev).generics().predicates().ty();
726 }
727 }
728 }
729 hir::ItemKind::Enum(_, _, ref def) => {
730 if let Some(item_ev) = item_ev {
731 self.reach(item.owner_id.def_id, item_ev).generics().predicates();
732 }
733 for variant in def.variants {
734 if let Some(item_ev) = item_ev {
735 self.update(variant.def_id, item_ev, Level::Reachable);
736 }
737
738 if let Some(variant_ev) = self.get(variant.def_id) {
739 if let Some(ctor_def_id) = variant.data.ctor_def_id() {
740 self.update(ctor_def_id, variant_ev, Level::Reachable);
741 }
742 for field in variant.data.fields() {
743 self.update(field.def_id, variant_ev, Level::Reachable);
744 self.reach(field.def_id, variant_ev).ty();
745 }
746 self.reach(item.owner_id.def_id, variant_ev).ty();
749 }
750 if let Some(ctor_def_id) = variant.data.ctor_def_id() {
751 if let Some(ctor_ev) = self.get(ctor_def_id) {
752 self.reach(item.owner_id.def_id, ctor_ev).ty();
753 }
754 }
755 }
756 }
757 hir::ItemKind::ForeignMod { items, .. } => {
758 for foreign_item in items {
759 if let Some(foreign_item_ev) = self.get(foreign_item.owner_id.def_id) {
760 self.reach(foreign_item.owner_id.def_id, foreign_item_ev)
761 .generics()
762 .predicates()
763 .ty();
764 }
765 }
766 }
767 hir::ItemKind::Struct(_, _, ref struct_def)
768 | hir::ItemKind::Union(_, _, ref struct_def) => {
769 if let Some(item_ev) = item_ev {
770 self.reach(item.owner_id.def_id, item_ev).generics().predicates();
771 for field in struct_def.fields() {
772 self.update(field.def_id, item_ev, Level::Reachable);
773 if let Some(field_ev) = self.get(field.def_id) {
774 self.reach(field.def_id, field_ev).ty();
775 }
776 }
777 }
778 if let Some(ctor_def_id) = struct_def.ctor_def_id() {
779 if let Some(item_ev) = item_ev {
780 self.update(ctor_def_id, item_ev, Level::Reachable);
781 }
782 if let Some(ctor_ev) = self.get(ctor_def_id) {
783 self.reach(item.owner_id.def_id, ctor_ev).ty();
784 }
785 }
786 }
787 }
788 }
789}
790
791impl ReachEverythingInTheInterfaceVisitor<'_, '_> {
792 fn generics(&mut self) -> &mut Self {
793 for param in &self.ev.tcx.generics_of(self.item_def_id).own_params {
794 if let GenericParamDefKind::Const { .. } = param.kind {
795 self.visit(self.ev.tcx.type_of(param.def_id).instantiate_identity());
796 }
797 if let Some(default) = param.default_value(self.ev.tcx) {
798 self.visit(default.instantiate_identity());
799 }
800 }
801 self
802 }
803
804 fn predicates(&mut self) -> &mut Self {
805 self.visit_predicates(self.ev.tcx.predicates_of(self.item_def_id));
806 self
807 }
808
809 fn ty(&mut self) -> &mut Self {
810 self.visit(self.ev.tcx.type_of(self.item_def_id).instantiate_identity());
811 self
812 }
813
814 fn trait_ref(&mut self) -> &mut Self {
815 if let Some(trait_ref) = self.ev.tcx.impl_trait_ref(self.item_def_id) {
816 self.visit_trait(trait_ref.instantiate_identity());
817 }
818 self
819 }
820}
821
822impl<'tcx> DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
823 fn tcx(&self) -> TyCtxt<'tcx> {
824 self.ev.tcx
825 }
826 fn visit_def_id(&mut self, def_id: DefId, _kind: &str, _descr: &dyn fmt::Display) {
827 if let Some(def_id) = def_id.as_local() {
828 let max_vis = (self.level != Level::ReachableThroughImplTrait)
832 .then(|| self.ev.tcx.local_visibility(def_id));
833 self.ev.update_eff_vis(def_id, self.effective_vis, max_vis, self.level);
834 }
835 }
836}
837
838pub struct TestReachabilityVisitor<'a, 'tcx> {
842 tcx: TyCtxt<'tcx>,
843 effective_visibilities: &'a EffectiveVisibilities,
844}
845
846impl<'a, 'tcx> TestReachabilityVisitor<'a, 'tcx> {
847 fn effective_visibility_diagnostic(&mut self, def_id: LocalDefId) {
848 if self.tcx.has_attr(def_id, sym::rustc_effective_visibility) {
849 let mut error_msg = String::new();
850 let span = self.tcx.def_span(def_id.to_def_id());
851 if let Some(effective_vis) = self.effective_visibilities.effective_vis(def_id) {
852 for level in Level::all_levels() {
853 let vis_str = effective_vis.at_level(level).to_string(def_id, self.tcx);
854 if level != Level::Direct {
855 error_msg.push_str(", ");
856 }
857 error_msg.push_str(&format!("{level:?}: {vis_str}"));
858 }
859 } else {
860 error_msg.push_str("not in the table");
861 }
862 self.tcx.dcx().emit_err(ReportEffectiveVisibility { span, descr: error_msg });
863 }
864 }
865}
866
867impl<'a, 'tcx> Visitor<'tcx> for TestReachabilityVisitor<'a, 'tcx> {
868 fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
869 self.effective_visibility_diagnostic(item.owner_id.def_id);
870
871 match item.kind {
872 hir::ItemKind::Enum(_, _, ref def) => {
873 for variant in def.variants.iter() {
874 self.effective_visibility_diagnostic(variant.def_id);
875 if let Some(ctor_def_id) = variant.data.ctor_def_id() {
876 self.effective_visibility_diagnostic(ctor_def_id);
877 }
878 for field in variant.data.fields() {
879 self.effective_visibility_diagnostic(field.def_id);
880 }
881 }
882 }
883 hir::ItemKind::Struct(_, _, ref def) | hir::ItemKind::Union(_, _, ref def) => {
884 if let Some(ctor_def_id) = def.ctor_def_id() {
885 self.effective_visibility_diagnostic(ctor_def_id);
886 }
887 for field in def.fields() {
888 self.effective_visibility_diagnostic(field.def_id);
889 }
890 }
891 _ => {}
892 }
893 }
894
895 fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem<'tcx>) {
896 self.effective_visibility_diagnostic(item.owner_id.def_id);
897 }
898 fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem<'tcx>) {
899 self.effective_visibility_diagnostic(item.owner_id.def_id);
900 }
901 fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
902 self.effective_visibility_diagnostic(item.owner_id.def_id);
903 }
904}
905
906struct NamePrivacyVisitor<'tcx> {
914 tcx: TyCtxt<'tcx>,
915 maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
916}
917
918impl<'tcx> NamePrivacyVisitor<'tcx> {
919 #[track_caller]
923 fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> {
924 self.maybe_typeck_results
925 .expect("`NamePrivacyVisitor::typeck_results` called outside of body")
926 }
927
928 fn check_field(
930 &mut self,
931 hir_id: hir::HirId, use_ctxt: Span, def: ty::AdtDef<'tcx>, field: &'tcx ty::FieldDef,
935 ) -> bool {
936 if def.is_enum() {
937 return true;
938 }
939
940 let ident = Ident::new(sym::dummy, use_ctxt);
942 let (_, def_id) = self.tcx.adjust_ident_and_get_scope(ident, def.did(), hir_id);
943 !field.vis.is_accessible_from(def_id, self.tcx)
944 }
945
946 fn emit_unreachable_field_error(
948 &mut self,
949 fields: Vec<(Symbol, Span, bool )>,
950 def: ty::AdtDef<'tcx>, update_syntax: Option<Span>,
952 struct_span: Span,
953 ) {
954 if def.is_enum() || fields.is_empty() {
955 return;
956 }
957
958 let Some(field_names) = listify(&fields[..], |(n, _, _)| format!("`{n}`")) else { return };
970 let span: MultiSpan = fields.iter().map(|(_, span, _)| *span).collect::<Vec<Span>>().into();
971
972 let rest_field_names: Vec<_> =
974 fields.iter().filter(|(_, _, is_present)| !is_present).map(|(n, _, _)| n).collect();
975 let rest_len = rest_field_names.len();
976 let rest_field_names =
977 listify(&rest_field_names[..], |n| format!("`{n}`")).unwrap_or_default();
978 let labels = fields
980 .iter()
981 .filter(|(_, _, is_present)| *is_present)
982 .map(|(_, span, _)| FieldIsPrivateLabel::Other { span: *span })
983 .chain(update_syntax.iter().map(|span| FieldIsPrivateLabel::IsUpdateSyntax {
984 span: *span,
985 rest_field_names: rest_field_names.clone(),
986 rest_len,
987 }))
988 .collect();
989
990 self.tcx.dcx().emit_err(FieldIsPrivate {
991 span,
992 struct_span: if self
993 .tcx
994 .sess
995 .source_map()
996 .is_multiline(fields[0].1.between(struct_span))
997 {
998 Some(struct_span)
999 } else {
1000 None
1001 },
1002 field_names,
1003 variant_descr: def.variant_descr(),
1004 def_path_str: self.tcx.def_path_str(def.did()),
1005 labels,
1006 len: fields.len(),
1007 });
1008 }
1009
1010 fn check_expanded_fields(
1011 &mut self,
1012 adt: ty::AdtDef<'tcx>,
1013 variant: &'tcx ty::VariantDef,
1014 fields: &[hir::ExprField<'tcx>],
1015 hir_id: hir::HirId,
1016 span: Span,
1017 struct_span: Span,
1018 ) {
1019 let mut failed_fields = vec![];
1020 for (vf_index, variant_field) in variant.fields.iter_enumerated() {
1021 let field =
1022 fields.iter().find(|f| self.typeck_results().field_index(f.hir_id) == vf_index);
1023 let (hir_id, use_ctxt, span) = match field {
1024 Some(field) => (field.hir_id, field.ident.span, field.span),
1025 None => (hir_id, span, span),
1026 };
1027 if self.check_field(hir_id, use_ctxt, adt, variant_field) {
1028 let name = match field {
1029 Some(field) => field.ident.name,
1030 None => variant_field.name,
1031 };
1032 failed_fields.push((name, span, field.is_some()));
1033 }
1034 }
1035 self.emit_unreachable_field_error(failed_fields, adt, Some(span), struct_span);
1036 }
1037}
1038
1039impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> {
1040 fn visit_nested_body(&mut self, body_id: hir::BodyId) {
1041 let new_typeck_results = self.tcx.typeck_body(body_id);
1042 if new_typeck_results.tainted_by_errors.is_some() {
1044 return;
1045 }
1046 let old_maybe_typeck_results = self.maybe_typeck_results.replace(new_typeck_results);
1047 self.visit_body(self.tcx.hir_body(body_id));
1048 self.maybe_typeck_results = old_maybe_typeck_results;
1049 }
1050
1051 fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
1052 if let hir::ExprKind::Struct(qpath, fields, ref base) = expr.kind {
1053 let res = self.typeck_results().qpath_res(qpath, expr.hir_id);
1054 let adt = self.typeck_results().expr_ty(expr).ty_adt_def().unwrap();
1055 let variant = adt.variant_of_res(res);
1056 match *base {
1057 hir::StructTailExpr::Base(base) => {
1058 self.check_expanded_fields(
1062 adt,
1063 variant,
1064 fields,
1065 base.hir_id,
1066 base.span,
1067 qpath.span(),
1068 );
1069 }
1070 hir::StructTailExpr::DefaultFields(span) => {
1071 self.check_expanded_fields(
1072 adt,
1073 variant,
1074 fields,
1075 expr.hir_id,
1076 span,
1077 qpath.span(),
1078 );
1079 }
1080 hir::StructTailExpr::None => {
1081 let mut failed_fields = vec![];
1082 for field in fields {
1083 let (hir_id, use_ctxt) = (field.hir_id, field.ident.span);
1084 let index = self.typeck_results().field_index(field.hir_id);
1085 if self.check_field(hir_id, use_ctxt, adt, &variant.fields[index]) {
1086 failed_fields.push((field.ident.name, field.ident.span, true));
1087 }
1088 }
1089 self.emit_unreachable_field_error(failed_fields, adt, None, qpath.span());
1090 }
1091 }
1092 }
1093
1094 intravisit::walk_expr(self, expr);
1095 }
1096
1097 fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) {
1098 if let PatKind::Struct(ref qpath, fields, _) = pat.kind {
1099 let res = self.typeck_results().qpath_res(qpath, pat.hir_id);
1100 let adt = self.typeck_results().pat_ty(pat).ty_adt_def().unwrap();
1101 let variant = adt.variant_of_res(res);
1102 let mut failed_fields = vec![];
1103 for field in fields {
1104 let (hir_id, use_ctxt) = (field.hir_id, field.ident.span);
1105 let index = self.typeck_results().field_index(field.hir_id);
1106 if self.check_field(hir_id, use_ctxt, adt, &variant.fields[index]) {
1107 failed_fields.push((field.ident.name, field.ident.span, true));
1108 }
1109 }
1110 self.emit_unreachable_field_error(failed_fields, adt, None, qpath.span());
1111 }
1112
1113 intravisit::walk_pat(self, pat);
1114 }
1115}
1116
1117struct TypePrivacyVisitor<'tcx> {
1124 tcx: TyCtxt<'tcx>,
1125 module_def_id: LocalModDefId,
1126 maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
1127 span: Span,
1128}
1129
1130impl<'tcx> TypePrivacyVisitor<'tcx> {
1131 fn item_is_accessible(&self, did: DefId) -> bool {
1132 self.tcx.visibility(did).is_accessible_from(self.module_def_id, self.tcx)
1133 }
1134
1135 fn check_expr_pat_type(&mut self, id: hir::HirId, span: Span) -> bool {
1137 self.span = span;
1138 let typeck_results = self
1139 .maybe_typeck_results
1140 .unwrap_or_else(|| span_bug!(span, "`hir::Expr` or `hir::Pat` outside of a body"));
1141 let result: ControlFlow<()> = try {
1142 self.visit(typeck_results.node_type(id))?;
1143 self.visit(typeck_results.node_args(id))?;
1144 if let Some(adjustments) = typeck_results.adjustments().get(id) {
1145 adjustments.iter().try_for_each(|adjustment| self.visit(adjustment.target))?;
1146 }
1147 };
1148 result.is_break()
1149 }
1150
1151 fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
1152 let is_error = !self.item_is_accessible(def_id);
1153 if is_error {
1154 self.tcx.dcx().emit_err(ItemIsPrivate { span: self.span, kind, descr: descr.into() });
1155 }
1156 is_error
1157 }
1158}
1159
1160impl<'tcx> rustc_ty_utils::sig_types::SpannedTypeVisitor<'tcx> for TypePrivacyVisitor<'tcx> {
1161 type Result = ControlFlow<()>;
1162 fn visit(&mut self, span: Span, value: impl TypeVisitable<TyCtxt<'tcx>>) -> Self::Result {
1163 self.span = span;
1164 value.visit_with(&mut self.skeleton())
1165 }
1166}
1167
1168impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
1169 fn visit_nested_body(&mut self, body_id: hir::BodyId) {
1170 let old_maybe_typeck_results =
1171 self.maybe_typeck_results.replace(self.tcx.typeck_body(body_id));
1172 self.visit_body(self.tcx.hir_body(body_id));
1173 self.maybe_typeck_results = old_maybe_typeck_results;
1174 }
1175
1176 fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
1177 self.span = hir_ty.span;
1178 if self
1179 .visit(
1180 self.maybe_typeck_results
1181 .unwrap_or_else(|| span_bug!(hir_ty.span, "`hir::Ty` outside of a body"))
1182 .node_type(hir_ty.hir_id),
1183 )
1184 .is_break()
1185 {
1186 return;
1187 }
1188
1189 intravisit::walk_ty(self, hir_ty);
1190 }
1191
1192 fn visit_infer(
1193 &mut self,
1194 inf_id: rustc_hir::HirId,
1195 inf_span: Span,
1196 _kind: InferKind<'tcx>,
1197 ) -> Self::Result {
1198 self.span = inf_span;
1199 if let Some(ty) = self
1200 .maybe_typeck_results
1201 .unwrap_or_else(|| span_bug!(inf_span, "Inference variable outside of a body"))
1202 .node_type_opt(inf_id)
1203 {
1204 if self.visit(ty).is_break() {
1205 return;
1206 }
1207 } else {
1208 }
1210
1211 self.visit_id(inf_id)
1212 }
1213
1214 fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
1216 if self.check_expr_pat_type(expr.hir_id, expr.span) {
1217 return;
1219 }
1220 match expr.kind {
1221 hir::ExprKind::Assign(_, rhs, _) | hir::ExprKind::Match(rhs, ..) => {
1222 if self.check_expr_pat_type(rhs.hir_id, rhs.span) {
1224 return;
1225 }
1226 }
1227 hir::ExprKind::MethodCall(segment, ..) => {
1228 self.span = segment.ident.span;
1230 let typeck_results = self
1231 .maybe_typeck_results
1232 .unwrap_or_else(|| span_bug!(self.span, "`hir::Expr` outside of a body"));
1233 if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) {
1234 if self.visit(self.tcx.type_of(def_id).instantiate_identity()).is_break() {
1235 return;
1236 }
1237 } else {
1238 self.tcx
1239 .dcx()
1240 .span_delayed_bug(expr.span, "no type-dependent def for method call");
1241 }
1242 }
1243 _ => {}
1244 }
1245
1246 intravisit::walk_expr(self, expr);
1247 }
1248
1249 fn visit_qpath(&mut self, qpath: &'tcx hir::QPath<'tcx>, id: hir::HirId, span: Span) {
1256 let def = match qpath {
1257 hir::QPath::Resolved(_, path) => match path.res {
1258 Res::Def(kind, def_id) => Some((kind, def_id)),
1259 _ => None,
1260 },
1261 hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => {
1262 match self.maybe_typeck_results {
1263 Some(typeck_results) => typeck_results.type_dependent_def(id),
1264 None => None,
1266 }
1267 }
1268 };
1269 let def = def.filter(|(kind, _)| {
1270 matches!(
1271 kind,
1272 DefKind::AssocFn | DefKind::AssocConst | DefKind::AssocTy | DefKind::Static { .. }
1273 )
1274 });
1275 if let Some((kind, def_id)) = def {
1276 let is_local_static =
1277 if let DefKind::Static { .. } = kind { def_id.is_local() } else { false };
1278 if !self.item_is_accessible(def_id) && !is_local_static {
1279 let name = match *qpath {
1280 hir::QPath::LangItem(it, ..) => {
1281 self.tcx.lang_items().get(it).map(|did| self.tcx.def_path_str(did))
1282 }
1283 hir::QPath::Resolved(_, path) => Some(self.tcx.def_path_str(path.res.def_id())),
1284 hir::QPath::TypeRelative(_, segment) => Some(segment.ident.to_string()),
1285 };
1286 let kind = self.tcx.def_descr(def_id);
1287 let sess = self.tcx.sess;
1288 let _ = match name {
1289 Some(name) => {
1290 sess.dcx().emit_err(ItemIsPrivate { span, kind, descr: (&name).into() })
1291 }
1292 None => sess.dcx().emit_err(UnnamedItemIsPrivate { span, kind }),
1293 };
1294 return;
1295 }
1296 }
1297
1298 intravisit::walk_qpath(self, qpath, id);
1299 }
1300
1301 fn visit_pat(&mut self, pattern: &'tcx hir::Pat<'tcx>) {
1303 if self.check_expr_pat_type(pattern.hir_id, pattern.span) {
1304 return;
1306 }
1307
1308 intravisit::walk_pat(self, pattern);
1309 }
1310
1311 fn visit_local(&mut self, local: &'tcx hir::LetStmt<'tcx>) {
1312 if let Some(init) = local.init {
1313 if self.check_expr_pat_type(init.hir_id, init.span) {
1314 return;
1316 }
1317 }
1318
1319 intravisit::walk_local(self, local);
1320 }
1321}
1322
1323impl<'tcx> DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> {
1324 type Result = ControlFlow<()>;
1325 fn tcx(&self) -> TyCtxt<'tcx> {
1326 self.tcx
1327 }
1328 fn visit_def_id(
1329 &mut self,
1330 def_id: DefId,
1331 kind: &str,
1332 descr: &dyn fmt::Display,
1333 ) -> Self::Result {
1334 if self.check_def_id(def_id, kind, descr) {
1335 ControlFlow::Break(())
1336 } else {
1337 ControlFlow::Continue(())
1338 }
1339 }
1340}
1341
1342struct SearchInterfaceForPrivateItemsVisitor<'tcx> {
1350 tcx: TyCtxt<'tcx>,
1351 item_def_id: LocalDefId,
1352 required_visibility: ty::Visibility,
1354 required_effective_vis: Option<EffectiveVisibility>,
1355 in_assoc_ty: bool,
1356 in_primary_interface: bool,
1357 skip_assoc_tys: bool,
1358}
1359
1360impl SearchInterfaceForPrivateItemsVisitor<'_> {
1361 fn generics(&mut self) -> &mut Self {
1362 self.in_primary_interface = true;
1363 for param in &self.tcx.generics_of(self.item_def_id).own_params {
1364 match param.kind {
1365 GenericParamDefKind::Lifetime => {}
1366 GenericParamDefKind::Type { has_default, .. } => {
1367 if has_default {
1368 let _ = self.visit(self.tcx.type_of(param.def_id).instantiate_identity());
1369 }
1370 }
1371 GenericParamDefKind::Const { .. } => {
1373 let _ = self.visit(self.tcx.type_of(param.def_id).instantiate_identity());
1374 }
1375 }
1376 }
1377 self
1378 }
1379
1380 fn predicates(&mut self) -> &mut Self {
1381 self.in_primary_interface = false;
1382 let _ = self.visit_predicates(self.tcx.explicit_predicates_of(self.item_def_id));
1389 self
1390 }
1391
1392 fn bounds(&mut self) -> &mut Self {
1393 self.in_primary_interface = false;
1394 let _ = self.visit_clauses(self.tcx.explicit_item_bounds(self.item_def_id).skip_binder());
1395 self
1396 }
1397
1398 fn ty(&mut self) -> &mut Self {
1399 self.in_primary_interface = true;
1400 let _ = self.visit(self.tcx.type_of(self.item_def_id).instantiate_identity());
1401 self
1402 }
1403
1404 fn trait_ref(&mut self) -> &mut Self {
1405 self.in_primary_interface = true;
1406 if let Some(trait_ref) = self.tcx.impl_trait_ref(self.item_def_id) {
1407 let _ = self.visit_trait(trait_ref.instantiate_identity());
1408 }
1409 self
1410 }
1411
1412 fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
1413 if self.leaks_private_dep(def_id) {
1414 self.tcx.emit_node_span_lint(
1415 lint::builtin::EXPORTED_PRIVATE_DEPENDENCIES,
1416 self.tcx.local_def_id_to_hir_id(self.item_def_id),
1417 self.tcx.def_span(self.item_def_id.to_def_id()),
1418 FromPrivateDependencyInPublicInterface {
1419 kind,
1420 descr: descr.into(),
1421 krate: self.tcx.crate_name(def_id.krate),
1422 },
1423 );
1424 }
1425
1426 let Some(local_def_id) = def_id.as_local() else {
1427 return false;
1428 };
1429
1430 let vis = self.tcx.local_visibility(local_def_id);
1431 let span = self.tcx.def_span(self.item_def_id.to_def_id());
1432 let vis_span = self.tcx.def_span(def_id);
1433 if self.in_assoc_ty && !vis.is_at_least(self.required_visibility, self.tcx) {
1434 let vis_descr = match vis {
1435 ty::Visibility::Public => "public",
1436 ty::Visibility::Restricted(vis_def_id) => {
1437 if vis_def_id
1438 == self.tcx.parent_module_from_def_id(local_def_id).to_local_def_id()
1439 {
1440 "private"
1441 } else if vis_def_id.is_top_level_module() {
1442 "crate-private"
1443 } else {
1444 "restricted"
1445 }
1446 }
1447 };
1448
1449 self.tcx.dcx().emit_err(InPublicInterface {
1450 span,
1451 vis_descr,
1452 kind,
1453 descr: descr.into(),
1454 vis_span,
1455 });
1456 return false;
1457 }
1458
1459 let Some(effective_vis) = self.required_effective_vis else {
1460 return false;
1461 };
1462
1463 let reachable_at_vis = *effective_vis.at_level(Level::Reachable);
1464
1465 if !vis.is_at_least(reachable_at_vis, self.tcx) {
1466 let lint = if self.in_primary_interface {
1467 lint::builtin::PRIVATE_INTERFACES
1468 } else {
1469 lint::builtin::PRIVATE_BOUNDS
1470 };
1471 self.tcx.emit_node_span_lint(
1472 lint,
1473 self.tcx.local_def_id_to_hir_id(self.item_def_id),
1474 span,
1475 PrivateInterfacesOrBoundsLint {
1476 item_span: span,
1477 item_kind: self.tcx.def_descr(self.item_def_id.to_def_id()),
1478 item_descr: (&LazyDefPathStr {
1479 def_id: self.item_def_id.to_def_id(),
1480 tcx: self.tcx,
1481 })
1482 .into(),
1483 item_vis_descr: &reachable_at_vis.to_string(self.item_def_id, self.tcx),
1484 ty_span: vis_span,
1485 ty_kind: kind,
1486 ty_descr: descr.into(),
1487 ty_vis_descr: &vis.to_string(local_def_id, self.tcx),
1488 },
1489 );
1490 }
1491
1492 false
1493 }
1494
1495 fn leaks_private_dep(&self, item_id: DefId) -> bool {
1500 let ret = self.required_visibility.is_public() && self.tcx.is_private_dep(item_id.krate);
1501
1502 debug!("leaks_private_dep(item_id={:?})={}", item_id, ret);
1503 ret
1504 }
1505}
1506
1507impl<'tcx> DefIdVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'tcx> {
1508 type Result = ControlFlow<()>;
1509 fn skip_assoc_tys(&self) -> bool {
1510 self.skip_assoc_tys
1511 }
1512 fn tcx(&self) -> TyCtxt<'tcx> {
1513 self.tcx
1514 }
1515 fn visit_def_id(
1516 &mut self,
1517 def_id: DefId,
1518 kind: &str,
1519 descr: &dyn fmt::Display,
1520 ) -> Self::Result {
1521 if self.check_def_id(def_id, kind, descr) {
1522 ControlFlow::Break(())
1523 } else {
1524 ControlFlow::Continue(())
1525 }
1526 }
1527}
1528
1529struct PrivateItemsInPublicInterfacesChecker<'a, 'tcx> {
1530 tcx: TyCtxt<'tcx>,
1531 effective_visibilities: &'a EffectiveVisibilities,
1532}
1533
1534impl<'tcx> PrivateItemsInPublicInterfacesChecker<'_, 'tcx> {
1535 fn check(
1536 &self,
1537 def_id: LocalDefId,
1538 required_visibility: ty::Visibility,
1539 required_effective_vis: Option<EffectiveVisibility>,
1540 ) -> SearchInterfaceForPrivateItemsVisitor<'tcx> {
1541 SearchInterfaceForPrivateItemsVisitor {
1542 tcx: self.tcx,
1543 item_def_id: def_id,
1544 required_visibility,
1545 required_effective_vis,
1546 in_assoc_ty: false,
1547 in_primary_interface: true,
1548 skip_assoc_tys: false,
1549 }
1550 }
1551
1552 fn check_unnameable(&self, def_id: LocalDefId, effective_vis: Option<EffectiveVisibility>) {
1553 let Some(effective_vis) = effective_vis else {
1554 return;
1555 };
1556
1557 let reexported_at_vis = effective_vis.at_level(Level::Reexported);
1558 let reachable_at_vis = effective_vis.at_level(Level::Reachable);
1559
1560 if reachable_at_vis.is_public() && reexported_at_vis != reachable_at_vis {
1561 let hir_id = self.tcx.local_def_id_to_hir_id(def_id);
1562 let span = self.tcx.def_span(def_id.to_def_id());
1563 self.tcx.emit_node_span_lint(
1564 lint::builtin::UNNAMEABLE_TYPES,
1565 hir_id,
1566 span,
1567 UnnameableTypesLint {
1568 span,
1569 kind: self.tcx.def_descr(def_id.to_def_id()),
1570 descr: (&LazyDefPathStr { def_id: def_id.to_def_id(), tcx: self.tcx }).into(),
1571 reachable_vis: &reachable_at_vis.to_string(def_id, self.tcx),
1572 reexported_vis: &reexported_at_vis.to_string(def_id, self.tcx),
1573 },
1574 );
1575 }
1576 }
1577
1578 fn check_assoc_item(
1579 &self,
1580 item: &ty::AssocItem,
1581 vis: ty::Visibility,
1582 effective_vis: Option<EffectiveVisibility>,
1583 ) {
1584 let mut check = self.check(item.def_id.expect_local(), vis, effective_vis);
1585
1586 let (check_ty, is_assoc_ty) = match item.kind {
1587 ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => (true, false),
1588 ty::AssocKind::Type { .. } => (item.defaultness(self.tcx).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 self.check_unnameable(def_id, effective_vis);
1623
1624 self.check(def_id, item_visibility, effective_vis).generics().predicates();
1625
1626 for assoc_item in tcx.associated_items(id.owner_id).in_definition_order() {
1627 if assoc_item.is_impl_trait_in_trait() {
1628 continue;
1629 }
1630
1631 self.check_assoc_item(assoc_item, item_visibility, effective_vis);
1632
1633 if assoc_item.is_type() {
1634 self.check(
1635 assoc_item.def_id.expect_local(),
1636 item_visibility,
1637 effective_vis,
1638 )
1639 .bounds();
1640 }
1641 }
1642 }
1643 DefKind::TraitAlias => {
1644 self.check(def_id, item_visibility, effective_vis).generics().predicates();
1645 }
1646 DefKind::Enum => {
1647 let item = tcx.hir_item(id);
1648 if let hir::ItemKind::Enum(_, _, ref def) = item.kind {
1649 self.check_unnameable(item.owner_id.def_id, effective_vis);
1650
1651 self.check(item.owner_id.def_id, item_visibility, effective_vis)
1652 .generics()
1653 .predicates();
1654
1655 for variant in def.variants {
1656 for field in variant.data.fields() {
1657 self.check(field.def_id, item_visibility, effective_vis).ty();
1658 }
1659 }
1660 }
1661 }
1662 DefKind::ForeignMod => {
1664 let item = tcx.hir_item(id);
1665 if let hir::ItemKind::ForeignMod { items, .. } = item.kind {
1666 for &foreign_item in items {
1667 let foreign_item = tcx.hir_foreign_item(foreign_item);
1668
1669 let ev = self.get(foreign_item.owner_id.def_id);
1670 let vis = tcx.local_visibility(foreign_item.owner_id.def_id);
1671
1672 if let ForeignItemKind::Type = foreign_item.kind {
1673 self.check_unnameable(foreign_item.owner_id.def_id, ev);
1674 }
1675
1676 self.check(foreign_item.owner_id.def_id, vis, ev)
1677 .generics()
1678 .predicates()
1679 .ty();
1680 }
1681 }
1682 }
1683 DefKind::Struct | DefKind::Union => {
1685 let item = tcx.hir_item(id);
1686 if let hir::ItemKind::Struct(_, _, ref struct_def)
1687 | hir::ItemKind::Union(_, _, ref struct_def) = item.kind
1688 {
1689 self.check_unnameable(item.owner_id.def_id, effective_vis);
1690 self.check(item.owner_id.def_id, item_visibility, effective_vis)
1691 .generics()
1692 .predicates();
1693
1694 for field in struct_def.fields() {
1695 let field_visibility = tcx.local_visibility(field.def_id);
1696 let field_ev = self.get(field.def_id);
1697
1698 self.check(
1699 field.def_id,
1700 min(item_visibility, field_visibility, tcx),
1701 field_ev,
1702 )
1703 .ty();
1704 }
1705 }
1706 }
1707 DefKind::Impl { of_trait } => {
1712 let impl_vis = ty::Visibility::of_impl::<false>(def_id, tcx, &Default::default());
1713
1714 let impl_ev =
1726 EffectiveVisibility::of_impl::<false>(def_id, tcx, self.effective_visibilities);
1727
1728 let mut check = self.check(def_id, impl_vis, Some(impl_ev));
1729
1730 if !of_trait {
1733 check.generics().predicates();
1734 }
1735
1736 check.skip_assoc_tys = true;
1740 check.ty().trait_ref();
1741
1742 for assoc_item in tcx.associated_items(id.owner_id).in_definition_order() {
1743 if assoc_item.is_impl_trait_in_trait() {
1744 continue;
1745 }
1746
1747 let impl_item_vis = if !of_trait {
1748 min(tcx.local_visibility(assoc_item.def_id.expect_local()), impl_vis, tcx)
1749 } else {
1750 impl_vis
1751 };
1752
1753 let impl_item_ev = if !of_trait {
1754 self.get(assoc_item.def_id.expect_local())
1755 .map(|ev| ev.min(impl_ev, self.tcx))
1756 } else {
1757 Some(impl_ev)
1758 };
1759
1760 self.check_assoc_item(assoc_item, impl_item_vis, impl_item_ev);
1761 }
1762 }
1763 _ => {}
1764 }
1765 }
1766}
1767
1768pub fn provide(providers: &mut Providers) {
1769 *providers = Providers {
1770 effective_visibilities,
1771 check_private_in_public,
1772 check_mod_privacy,
1773 ..*providers
1774 };
1775}
1776
1777fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
1778 let mut visitor = NamePrivacyVisitor { tcx, maybe_typeck_results: None };
1780 tcx.hir_visit_item_likes_in_module(module_def_id, &mut visitor);
1781
1782 let span = tcx.def_span(module_def_id);
1785 let mut visitor = TypePrivacyVisitor { tcx, module_def_id, maybe_typeck_results: None, span };
1786
1787 let module = tcx.hir_module_items(module_def_id);
1788 for def_id in module.definitions() {
1789 let _ = rustc_ty_utils::sig_types::walk_types(tcx, def_id, &mut visitor);
1790
1791 if let Some(body_id) = tcx.hir_maybe_body_owned_by(def_id) {
1792 visitor.visit_nested_body(body_id.id());
1793 }
1794 }
1795
1796 for id in module.free_items() {
1797 if let ItemKind::Impl(i) = tcx.hir_item(id).kind {
1798 if let Some(item) = i.of_trait {
1799 let trait_ref = tcx.impl_trait_ref(id.owner_id.def_id).unwrap();
1800 let trait_ref = trait_ref.instantiate_identity();
1801 visitor.span = item.path.span;
1802 let _ = visitor.visit_def_id(
1803 trait_ref.def_id,
1804 "trait",
1805 &trait_ref.print_only_trait_path(),
1806 );
1807 }
1808 }
1809 }
1810}
1811
1812fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities {
1813 let mut visitor = EmbargoVisitor {
1816 tcx,
1817 effective_visibilities: tcx.resolutions(()).effective_visibilities.clone(),
1818 macro_reachable: Default::default(),
1819 changed: false,
1820 };
1821
1822 visitor.effective_visibilities.check_invariants(tcx);
1823
1824 let impl_trait_pass = !tcx.sess.opts.actually_rustdoc;
1828 if impl_trait_pass {
1829 let krate = tcx.hir_crate_items(());
1832 for id in krate.opaques() {
1833 let opaque = tcx.hir_node_by_def_id(id).expect_opaque_ty();
1834 let should_visit = match opaque.origin {
1835 hir::OpaqueTyOrigin::FnReturn {
1836 parent,
1837 in_trait_or_impl: Some(hir::RpitContext::Trait),
1838 }
1839 | hir::OpaqueTyOrigin::AsyncFn {
1840 parent,
1841 in_trait_or_impl: Some(hir::RpitContext::Trait),
1842 } => match tcx.hir_node_by_def_id(parent).expect_trait_item().expect_fn().1 {
1843 hir::TraitFn::Required(_) => false,
1844 hir::TraitFn::Provided(..) => true,
1845 },
1846
1847 hir::OpaqueTyOrigin::FnReturn {
1850 in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
1851 ..
1852 }
1853 | hir::OpaqueTyOrigin::AsyncFn {
1854 in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
1855 ..
1856 }
1857 | hir::OpaqueTyOrigin::TyAlias { .. } => true,
1858 };
1859 if should_visit {
1860 let pub_ev = EffectiveVisibility::from_vis(ty::Visibility::Public);
1864 visitor
1865 .reach_through_impl_trait(opaque.def_id, pub_ev)
1866 .generics()
1867 .predicates()
1868 .ty();
1869 }
1870 }
1871
1872 visitor.changed = false;
1873 }
1874
1875 loop {
1876 tcx.hir_visit_all_item_likes_in_crate(&mut visitor);
1877 if visitor.changed {
1878 visitor.changed = false;
1879 } else {
1880 break;
1881 }
1882 }
1883 visitor.effective_visibilities.check_invariants(tcx);
1884
1885 let mut check_visitor =
1886 TestReachabilityVisitor { tcx, effective_visibilities: &visitor.effective_visibilities };
1887 check_visitor.effective_visibility_diagnostic(CRATE_DEF_ID);
1888 tcx.hir_visit_all_item_likes_in_crate(&mut check_visitor);
1889
1890 tcx.arena.alloc(visitor.effective_visibilities)
1891}
1892
1893fn check_private_in_public(tcx: TyCtxt<'_>, (): ()) {
1894 let effective_visibilities = tcx.effective_visibilities(());
1895 let mut checker = PrivateItemsInPublicInterfacesChecker { tcx, effective_visibilities };
1897
1898 for id in tcx.hir_free_items() {
1899 checker.check_item(id);
1900 }
1901}