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