1#![allow(internal_features)]
3#![cfg_attr(doc, recursion_limit = "256")] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
5#![doc(rust_logo)]
6#![feature(associated_type_defaults)]
7#![feature(let_chains)]
8#![feature(rustdoc_internals)]
9#![feature(try_blocks)]
10mod errors;
13
14use std::fmt;
15use std::marker::PhantomData;
16use std::ops::ControlFlow;
17
18use errors::{
19 FieldIsPrivate, FieldIsPrivateLabel, FromPrivateDependencyInPublicInterface, InPublicInterface,
20 ItemIsPrivate, PrivateInterfacesOrBoundsLint, ReportEffectiveVisibility, UnnameableTypesLint,
21 UnnamedItemIsPrivate,
22};
23use rustc_ast::MacroDef;
24use rustc_ast::visit::{VisitorResult, try_visit};
25use rustc_attr_parsing::AttributeKind;
26use rustc_data_structures::fx::FxHashSet;
27use rustc_data_structures::intern::Interned;
28use rustc_errors::{MultiSpan, listify};
29use rustc_hir::def::{DefKind, Res};
30use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId, LocalModDefId};
31use rustc_hir::intravisit::{self, InferKind, Visitor};
32use rustc_hir::{AmbigArg, AssocItemKind, ForeignItemKind, ItemId, ItemKind, PatKind};
33use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, Level};
34use rustc_middle::query::Providers;
35use rustc_middle::ty::print::PrintTraitRefExt as _;
36use rustc_middle::ty::{
37 self, Const, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
38 TypeVisitor,
39};
40use rustc_middle::{bug, span_bug};
41use rustc_session::lint;
42use rustc_span::hygiene::Transparency;
43use rustc_span::{Ident, Span, Symbol, sym};
44use tracing::debug;
45use {rustc_attr_parsing as attr, rustc_hir as hir};
46
47rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
48
49struct LazyDefPathStr<'tcx> {
54 def_id: DefId,
55 tcx: TyCtxt<'tcx>,
56}
57
58impl<'tcx> fmt::Display for LazyDefPathStr<'tcx> {
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 write!(f, "{}", self.tcx.def_path_str(self.def_id))
61 }
62}
63
64pub trait DefIdVisitor<'tcx> {
73 type Result: VisitorResult = ();
74 const SHALLOW: bool = false;
75 const SKIP_ASSOC_TYS: bool = false;
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(arg) => arg.visit_with(self),
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::Weak | ty::Projection), data) => {
216 if V::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::Weak => "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 const SKIP_ASSOC_TYS: bool = true;
328 fn tcx(&self) -> TyCtxt<'tcx> {
329 self.tcx
330 }
331 fn visit_def_id(&mut self, def_id: DefId, _kind: &str, _descr: &dyn fmt::Display) {
332 if let Some(def_id) = def_id.as_local() {
333 self.min = VL::new_min(self, def_id);
334 }
335 }
336}
337
338trait VisibilityLike: Sized {
339 const MAX: Self;
340 fn new_min<const SHALLOW: bool>(
341 find: &FindMin<'_, '_, Self, SHALLOW>,
342 def_id: LocalDefId,
343 ) -> Self;
344
345 fn of_impl<const SHALLOW: bool>(
348 def_id: LocalDefId,
349 tcx: TyCtxt<'_>,
350 effective_visibilities: &EffectiveVisibilities,
351 ) -> Self {
352 let mut find = FindMin::<_, SHALLOW> { tcx, effective_visibilities, min: Self::MAX };
353 find.visit(tcx.type_of(def_id).instantiate_identity());
354 if let Some(trait_ref) = tcx.impl_trait_ref(def_id) {
355 find.visit_trait(trait_ref.instantiate_identity());
356 }
357 find.min
358 }
359}
360
361impl VisibilityLike for ty::Visibility {
362 const MAX: Self = ty::Visibility::Public;
363 fn new_min<const SHALLOW: bool>(
364 find: &FindMin<'_, '_, Self, SHALLOW>,
365 def_id: LocalDefId,
366 ) -> Self {
367 min(find.tcx.local_visibility(def_id), find.min, find.tcx)
368 }
369}
370
371impl VisibilityLike for EffectiveVisibility {
372 const MAX: Self = EffectiveVisibility::from_vis(ty::Visibility::Public);
373 fn new_min<const SHALLOW: bool>(
374 find: &FindMin<'_, '_, Self, SHALLOW>,
375 def_id: LocalDefId,
376 ) -> Self {
377 let effective_vis =
378 find.effective_visibilities.effective_vis(def_id).copied().unwrap_or_else(|| {
379 let private_vis = ty::Visibility::Restricted(
380 find.tcx.parent_module_from_def_id(def_id).to_local_def_id(),
381 );
382 EffectiveVisibility::from_vis(private_vis)
383 });
384
385 effective_vis.min(find.min, find.tcx)
386 }
387}
388
389struct EmbargoVisitor<'tcx> {
394 tcx: TyCtxt<'tcx>,
395
396 effective_visibilities: EffectiveVisibilities,
398 macro_reachable: FxHashSet<(LocalModDefId, LocalModDefId)>,
411 changed: bool,
413}
414
415struct ReachEverythingInTheInterfaceVisitor<'a, 'tcx> {
416 effective_vis: EffectiveVisibility,
417 item_def_id: LocalDefId,
418 ev: &'a mut EmbargoVisitor<'tcx>,
419 level: Level,
420}
421
422impl<'tcx> EmbargoVisitor<'tcx> {
423 fn get(&self, def_id: LocalDefId) -> Option<EffectiveVisibility> {
424 self.effective_visibilities.effective_vis(def_id).copied()
425 }
426
427 fn update(
429 &mut self,
430 def_id: LocalDefId,
431 inherited_effective_vis: EffectiveVisibility,
432 level: Level,
433 ) {
434 let nominal_vis = self.tcx.local_visibility(def_id);
435 self.update_eff_vis(def_id, inherited_effective_vis, Some(nominal_vis), level);
436 }
437
438 fn update_eff_vis(
439 &mut self,
440 def_id: LocalDefId,
441 inherited_effective_vis: EffectiveVisibility,
442 max_vis: Option<ty::Visibility>,
443 level: Level,
444 ) {
445 let private_vis =
447 ty::Visibility::Restricted(self.tcx.parent_module_from_def_id(def_id).into());
448 if max_vis != Some(private_vis) {
449 self.changed |= self.effective_visibilities.update(
450 def_id,
451 max_vis,
452 || private_vis,
453 inherited_effective_vis,
454 level,
455 self.tcx,
456 );
457 }
458 }
459
460 fn reach(
461 &mut self,
462 def_id: LocalDefId,
463 effective_vis: EffectiveVisibility,
464 ) -> ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
465 ReachEverythingInTheInterfaceVisitor {
466 effective_vis,
467 item_def_id: def_id,
468 ev: self,
469 level: Level::Reachable,
470 }
471 }
472
473 fn reach_through_impl_trait(
474 &mut self,
475 def_id: LocalDefId,
476 effective_vis: EffectiveVisibility,
477 ) -> ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
478 ReachEverythingInTheInterfaceVisitor {
479 effective_vis,
480 item_def_id: def_id,
481 ev: self,
482 level: Level::ReachableThroughImplTrait,
483 }
484 }
485
486 fn update_reachability_from_macro(
489 &mut self,
490 local_def_id: LocalDefId,
491 md: &MacroDef,
492 macro_ev: EffectiveVisibility,
493 ) {
494 let hir_id = self.tcx.local_def_id_to_hir_id(local_def_id);
496 let attrs = self.tcx.hir_attrs(hir_id);
497
498 if attr::find_attr!(attrs, AttributeKind::MacroTransparency(x) => *x)
499 .unwrap_or(Transparency::fallback(md.macro_rules))
500 != Transparency::Opaque
501 {
502 return;
503 }
504
505 let macro_module_def_id = self.tcx.local_parent(local_def_id);
506 if self.tcx.def_kind(macro_module_def_id) != DefKind::Mod {
507 return;
509 }
510 let macro_module_def_id = LocalModDefId::new_unchecked(macro_module_def_id);
512
513 if self.effective_visibilities.public_at_level(local_def_id).is_none() {
514 return;
515 }
516
517 let mut module_def_id = macro_module_def_id;
520 loop {
521 let changed_reachability =
522 self.update_macro_reachable(module_def_id, macro_module_def_id, macro_ev);
523 if changed_reachability || module_def_id == LocalModDefId::CRATE_DEF_ID {
524 break;
525 }
526 module_def_id = LocalModDefId::new_unchecked(self.tcx.local_parent(module_def_id));
527 }
528 }
529
530 fn update_macro_reachable(
533 &mut self,
534 module_def_id: LocalModDefId,
535 defining_mod: LocalModDefId,
536 macro_ev: EffectiveVisibility,
537 ) -> bool {
538 if self.macro_reachable.insert((module_def_id, defining_mod)) {
539 for child in self.tcx.module_children_local(module_def_id.to_local_def_id()) {
540 if let Res::Def(def_kind, def_id) = child.res
541 && let Some(def_id) = def_id.as_local()
542 && child.vis.is_accessible_from(defining_mod, self.tcx)
543 {
544 let vis = self.tcx.local_visibility(def_id);
545 self.update_macro_reachable_def(def_id, def_kind, vis, defining_mod, macro_ev);
546 }
547 }
548 true
549 } else {
550 false
551 }
552 }
553
554 fn update_macro_reachable_def(
555 &mut self,
556 def_id: LocalDefId,
557 def_kind: DefKind,
558 vis: ty::Visibility,
559 module: LocalModDefId,
560 macro_ev: EffectiveVisibility,
561 ) {
562 self.update(def_id, macro_ev, Level::Reachable);
563 match def_kind {
564 DefKind::Const | DefKind::Static { .. } | DefKind::TraitAlias | DefKind::TyAlias => {
566 if vis.is_accessible_from(module, self.tcx) {
567 self.update(def_id, macro_ev, Level::Reachable);
568 }
569 }
570
571 DefKind::Macro(_) => {
576 let item = self.tcx.hir_expect_item(def_id);
577 if let hir::ItemKind::Macro(_, MacroDef { macro_rules: false, .. }, _) = item.kind {
578 if vis.is_accessible_from(module, self.tcx) {
579 self.update(def_id, macro_ev, Level::Reachable);
580 }
581 }
582 }
583
584 DefKind::Mod => {
589 if vis.is_accessible_from(module, self.tcx) {
590 self.update_macro_reachable(
591 LocalModDefId::new_unchecked(def_id),
592 module,
593 macro_ev,
594 );
595 }
596 }
597
598 DefKind::Struct | DefKind::Union => {
599 let item = self.tcx.hir_expect_item(def_id);
601 if let hir::ItemKind::Struct(_, ref struct_def, _)
602 | hir::ItemKind::Union(_, ref struct_def, _) = item.kind
603 {
604 for field in struct_def.fields() {
605 let field_vis = self.tcx.local_visibility(field.def_id);
606 if field_vis.is_accessible_from(module, self.tcx) {
607 self.reach(field.def_id, macro_ev).ty();
608 }
609 }
610 } else {
611 bug!("item {:?} with DefKind {:?}", item, def_kind);
612 }
613 }
614
615 DefKind::AssocConst
618 | DefKind::AssocTy
619 | DefKind::ConstParam
620 | DefKind::Ctor(_, _)
621 | DefKind::Enum
622 | DefKind::ForeignTy
623 | DefKind::Fn
624 | DefKind::OpaqueTy
625 | DefKind::AssocFn
626 | DefKind::Trait
627 | DefKind::TyParam
628 | DefKind::Variant
629 | DefKind::LifetimeParam
630 | DefKind::ExternCrate
631 | DefKind::Use
632 | DefKind::ForeignMod
633 | DefKind::AnonConst
634 | DefKind::InlineConst
635 | DefKind::Field
636 | DefKind::GlobalAsm
637 | DefKind::Impl { .. }
638 | DefKind::Closure
639 | DefKind::SyntheticCoroutineBody => (),
640 }
641 }
642}
643
644impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
645 fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
646 let item_ev = self.get(item.owner_id.def_id);
649 match item.kind {
650 hir::ItemKind::Use(..)
652 | hir::ItemKind::ExternCrate(..)
653 | hir::ItemKind::GlobalAsm { .. } => {}
654 hir::ItemKind::Mod(..) => {}
656 hir::ItemKind::Macro(_, macro_def, _) => {
657 if let Some(item_ev) = item_ev {
658 self.update_reachability_from_macro(item.owner_id.def_id, macro_def, item_ev);
659 }
660 }
661 hir::ItemKind::Const(..)
662 | hir::ItemKind::Static(..)
663 | hir::ItemKind::Fn { .. }
664 | hir::ItemKind::TyAlias(..) => {
665 if let Some(item_ev) = item_ev {
666 self.reach(item.owner_id.def_id, item_ev).generics().predicates().ty();
667 }
668 }
669 hir::ItemKind::Trait(.., trait_item_refs) => {
670 if let Some(item_ev) = item_ev {
671 self.reach(item.owner_id.def_id, item_ev).generics().predicates();
672
673 for trait_item_ref in trait_item_refs {
674 self.update(trait_item_ref.id.owner_id.def_id, item_ev, Level::Reachable);
675
676 let tcx = self.tcx;
677 let mut reach = self.reach(trait_item_ref.id.owner_id.def_id, item_ev);
678 reach.generics().predicates();
679
680 if trait_item_ref.kind == AssocItemKind::Type
681 && !tcx.defaultness(trait_item_ref.id.owner_id).has_value()
682 {
683 } else {
685 reach.ty();
686 }
687 }
688 }
689 }
690 hir::ItemKind::TraitAlias(..) => {
691 if let Some(item_ev) = item_ev {
692 self.reach(item.owner_id.def_id, item_ev).generics().predicates();
693 }
694 }
695 hir::ItemKind::Impl(impl_) => {
696 let item_ev = EffectiveVisibility::of_impl::<true>(
707 item.owner_id.def_id,
708 self.tcx,
709 &self.effective_visibilities,
710 );
711
712 self.update_eff_vis(item.owner_id.def_id, item_ev, None, Level::Direct);
713
714 self.reach(item.owner_id.def_id, item_ev).generics().predicates().ty().trait_ref();
715
716 for impl_item_ref in impl_.items {
717 let def_id = impl_item_ref.id.owner_id.def_id;
718 let max_vis =
719 impl_.of_trait.is_none().then(|| self.tcx.local_visibility(def_id));
720 self.update_eff_vis(def_id, item_ev, max_vis, Level::Direct);
721
722 if let Some(impl_item_ev) = self.get(def_id) {
723 self.reach(def_id, impl_item_ev).generics().predicates().ty();
724 }
725 }
726 }
727 hir::ItemKind::Enum(_, ref def, _) => {
728 if let Some(item_ev) = item_ev {
729 self.reach(item.owner_id.def_id, item_ev).generics().predicates();
730 }
731 for variant in def.variants {
732 if let Some(item_ev) = item_ev {
733 self.update(variant.def_id, item_ev, Level::Reachable);
734 }
735
736 if let Some(variant_ev) = self.get(variant.def_id) {
737 if let Some(ctor_def_id) = variant.data.ctor_def_id() {
738 self.update(ctor_def_id, variant_ev, Level::Reachable);
739 }
740 for field in variant.data.fields() {
741 self.update(field.def_id, variant_ev, Level::Reachable);
742 self.reach(field.def_id, variant_ev).ty();
743 }
744 self.reach(item.owner_id.def_id, variant_ev).ty();
747 }
748 if let Some(ctor_def_id) = variant.data.ctor_def_id() {
749 if let Some(ctor_ev) = self.get(ctor_def_id) {
750 self.reach(item.owner_id.def_id, ctor_ev).ty();
751 }
752 }
753 }
754 }
755 hir::ItemKind::ForeignMod { items, .. } => {
756 for foreign_item in items {
757 if let Some(foreign_item_ev) = self.get(foreign_item.id.owner_id.def_id) {
758 self.reach(foreign_item.id.owner_id.def_id, foreign_item_ev)
759 .generics()
760 .predicates()
761 .ty();
762 }
763 }
764 }
765 hir::ItemKind::Struct(_, ref struct_def, _)
766 | hir::ItemKind::Union(_, ref struct_def, _) => {
767 if let Some(item_ev) = item_ev {
768 self.reach(item.owner_id.def_id, item_ev).generics().predicates();
769 for field in struct_def.fields() {
770 self.update(field.def_id, item_ev, Level::Reachable);
771 if let Some(field_ev) = self.get(field.def_id) {
772 self.reach(field.def_id, field_ev).ty();
773 }
774 }
775 }
776 if let Some(ctor_def_id) = struct_def.ctor_def_id() {
777 if let Some(item_ev) = item_ev {
778 self.update(ctor_def_id, item_ev, Level::Reachable);
779 }
780 if let Some(ctor_ev) = self.get(ctor_def_id) {
781 self.reach(item.owner_id.def_id, ctor_ev).ty();
782 }
783 }
784 }
785 }
786 }
787}
788
789impl ReachEverythingInTheInterfaceVisitor<'_, '_> {
790 fn generics(&mut self) -> &mut Self {
791 for param in &self.ev.tcx.generics_of(self.item_def_id).own_params {
792 if let GenericParamDefKind::Const { .. } = param.kind {
793 self.visit(self.ev.tcx.type_of(param.def_id).instantiate_identity());
794 }
795 if let Some(default) = param.default_value(self.ev.tcx) {
796 self.visit(default.instantiate_identity());
797 }
798 }
799 self
800 }
801
802 fn predicates(&mut self) -> &mut Self {
803 self.visit_predicates(self.ev.tcx.predicates_of(self.item_def_id));
804 self
805 }
806
807 fn ty(&mut self) -> &mut Self {
808 self.visit(self.ev.tcx.type_of(self.item_def_id).instantiate_identity());
809 self
810 }
811
812 fn trait_ref(&mut self) -> &mut Self {
813 if let Some(trait_ref) = self.ev.tcx.impl_trait_ref(self.item_def_id) {
814 self.visit_trait(trait_ref.instantiate_identity());
815 }
816 self
817 }
818}
819
820impl<'tcx> DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
821 fn tcx(&self) -> TyCtxt<'tcx> {
822 self.ev.tcx
823 }
824 fn visit_def_id(&mut self, def_id: DefId, _kind: &str, _descr: &dyn fmt::Display) {
825 if let Some(def_id) = def_id.as_local() {
826 let max_vis = (self.level != Level::ReachableThroughImplTrait)
830 .then(|| self.ev.tcx.local_visibility(def_id));
831 self.ev.update_eff_vis(def_id, self.effective_vis, max_vis, self.level);
832 }
833 }
834}
835
836pub struct TestReachabilityVisitor<'a, 'tcx> {
840 tcx: TyCtxt<'tcx>,
841 effective_visibilities: &'a EffectiveVisibilities,
842}
843
844impl<'a, 'tcx> TestReachabilityVisitor<'a, 'tcx> {
845 fn effective_visibility_diagnostic(&mut self, def_id: LocalDefId) {
846 if self.tcx.has_attr(def_id, sym::rustc_effective_visibility) {
847 let mut error_msg = String::new();
848 let span = self.tcx.def_span(def_id.to_def_id());
849 if let Some(effective_vis) = self.effective_visibilities.effective_vis(def_id) {
850 for level in Level::all_levels() {
851 let vis_str = effective_vis.at_level(level).to_string(def_id, self.tcx);
852 if level != Level::Direct {
853 error_msg.push_str(", ");
854 }
855 error_msg.push_str(&format!("{level:?}: {vis_str}"));
856 }
857 } else {
858 error_msg.push_str("not in the table");
859 }
860 self.tcx.dcx().emit_err(ReportEffectiveVisibility { span, descr: error_msg });
861 }
862 }
863}
864
865impl<'a, 'tcx> Visitor<'tcx> for TestReachabilityVisitor<'a, 'tcx> {
866 fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
867 self.effective_visibility_diagnostic(item.owner_id.def_id);
868
869 match item.kind {
870 hir::ItemKind::Enum(_, ref def, _) => {
871 for variant in def.variants.iter() {
872 self.effective_visibility_diagnostic(variant.def_id);
873 if let Some(ctor_def_id) = variant.data.ctor_def_id() {
874 self.effective_visibility_diagnostic(ctor_def_id);
875 }
876 for field in variant.data.fields() {
877 self.effective_visibility_diagnostic(field.def_id);
878 }
879 }
880 }
881 hir::ItemKind::Struct(_, ref def, _) | hir::ItemKind::Union(_, ref def, _) => {
882 if let Some(ctor_def_id) = def.ctor_def_id() {
883 self.effective_visibility_diagnostic(ctor_def_id);
884 }
885 for field in def.fields() {
886 self.effective_visibility_diagnostic(field.def_id);
887 }
888 }
889 _ => {}
890 }
891 }
892
893 fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem<'tcx>) {
894 self.effective_visibility_diagnostic(item.owner_id.def_id);
895 }
896 fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem<'tcx>) {
897 self.effective_visibility_diagnostic(item.owner_id.def_id);
898 }
899 fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
900 self.effective_visibility_diagnostic(item.owner_id.def_id);
901 }
902}
903
904struct NamePrivacyVisitor<'tcx> {
912 tcx: TyCtxt<'tcx>,
913 maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
914}
915
916impl<'tcx> NamePrivacyVisitor<'tcx> {
917 #[track_caller]
921 fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> {
922 self.maybe_typeck_results
923 .expect("`NamePrivacyVisitor::typeck_results` called outside of body")
924 }
925
926 fn check_field(
928 &mut self,
929 hir_id: hir::HirId, use_ctxt: Span, def: ty::AdtDef<'tcx>, field: &'tcx ty::FieldDef,
933 ) -> bool {
934 if def.is_enum() {
935 return true;
936 }
937
938 let ident = Ident::new(sym::dummy, use_ctxt);
940 let (_, def_id) = self.tcx.adjust_ident_and_get_scope(ident, def.did(), hir_id);
941 !field.vis.is_accessible_from(def_id, self.tcx)
942 }
943
944 fn emit_unreachable_field_error(
946 &mut self,
947 fields: Vec<(Symbol, Span, bool )>,
948 def: ty::AdtDef<'tcx>, update_syntax: Option<Span>,
950 struct_span: Span,
951 ) {
952 if def.is_enum() || fields.is_empty() {
953 return;
954 }
955
956 let Some(field_names) = listify(&fields[..], |(n, _, _)| format!("`{n}`")) else { return };
968 let span: MultiSpan = fields.iter().map(|(_, span, _)| *span).collect::<Vec<Span>>().into();
969
970 let rest_field_names: Vec<_> =
972 fields.iter().filter(|(_, _, is_present)| !is_present).map(|(n, _, _)| n).collect();
973 let rest_len = rest_field_names.len();
974 let rest_field_names =
975 listify(&rest_field_names[..], |n| format!("`{n}`")).unwrap_or_default();
976 let labels = fields
978 .iter()
979 .filter(|(_, _, is_present)| *is_present)
980 .map(|(_, span, _)| FieldIsPrivateLabel::Other { span: *span })
981 .chain(update_syntax.iter().map(|span| FieldIsPrivateLabel::IsUpdateSyntax {
982 span: *span,
983 rest_field_names: rest_field_names.clone(),
984 rest_len,
985 }))
986 .collect();
987
988 self.tcx.dcx().emit_err(FieldIsPrivate {
989 span,
990 struct_span: if self
991 .tcx
992 .sess
993 .source_map()
994 .is_multiline(fields[0].1.between(struct_span))
995 {
996 Some(struct_span)
997 } else {
998 None
999 },
1000 field_names,
1001 variant_descr: def.variant_descr(),
1002 def_path_str: self.tcx.def_path_str(def.did()),
1003 labels,
1004 len: fields.len(),
1005 });
1006 }
1007
1008 fn check_expanded_fields(
1009 &mut self,
1010 adt: ty::AdtDef<'tcx>,
1011 variant: &'tcx ty::VariantDef,
1012 fields: &[hir::ExprField<'tcx>],
1013 hir_id: hir::HirId,
1014 span: Span,
1015 struct_span: Span,
1016 ) {
1017 let mut failed_fields = vec![];
1018 for (vf_index, variant_field) in variant.fields.iter_enumerated() {
1019 let field =
1020 fields.iter().find(|f| self.typeck_results().field_index(f.hir_id) == vf_index);
1021 let (hir_id, use_ctxt, span) = match field {
1022 Some(field) => (field.hir_id, field.ident.span, field.span),
1023 None => (hir_id, span, span),
1024 };
1025 if self.check_field(hir_id, use_ctxt, adt, variant_field) {
1026 let name = match field {
1027 Some(field) => field.ident.name,
1028 None => variant_field.name,
1029 };
1030 failed_fields.push((name, span, field.is_some()));
1031 }
1032 }
1033 self.emit_unreachable_field_error(failed_fields, adt, Some(span), struct_span);
1034 }
1035}
1036
1037impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> {
1038 fn visit_nested_body(&mut self, body_id: hir::BodyId) {
1039 let new_typeck_results = self.tcx.typeck_body(body_id);
1040 if new_typeck_results.tainted_by_errors.is_some() {
1042 return;
1043 }
1044 let old_maybe_typeck_results = self.maybe_typeck_results.replace(new_typeck_results);
1045 self.visit_body(self.tcx.hir_body(body_id));
1046 self.maybe_typeck_results = old_maybe_typeck_results;
1047 }
1048
1049 fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
1050 if let hir::ExprKind::Struct(qpath, fields, ref base) = expr.kind {
1051 let res = self.typeck_results().qpath_res(qpath, expr.hir_id);
1052 let adt = self.typeck_results().expr_ty(expr).ty_adt_def().unwrap();
1053 let variant = adt.variant_of_res(res);
1054 match *base {
1055 hir::StructTailExpr::Base(base) => {
1056 self.check_expanded_fields(
1060 adt,
1061 variant,
1062 fields,
1063 base.hir_id,
1064 base.span,
1065 qpath.span(),
1066 );
1067 }
1068 hir::StructTailExpr::DefaultFields(span) => {
1069 self.check_expanded_fields(
1070 adt,
1071 variant,
1072 fields,
1073 expr.hir_id,
1074 span,
1075 qpath.span(),
1076 );
1077 }
1078 hir::StructTailExpr::None => {
1079 let mut failed_fields = vec![];
1080 for field in fields {
1081 let (hir_id, use_ctxt) = (field.hir_id, field.ident.span);
1082 let index = self.typeck_results().field_index(field.hir_id);
1083 if self.check_field(hir_id, use_ctxt, adt, &variant.fields[index]) {
1084 failed_fields.push((field.ident.name, field.ident.span, true));
1085 }
1086 }
1087 self.emit_unreachable_field_error(failed_fields, adt, None, qpath.span());
1088 }
1089 }
1090 }
1091
1092 intravisit::walk_expr(self, expr);
1093 }
1094
1095 fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) {
1096 if let PatKind::Struct(ref qpath, fields, _) = pat.kind {
1097 let res = self.typeck_results().qpath_res(qpath, pat.hir_id);
1098 let adt = self.typeck_results().pat_ty(pat).ty_adt_def().unwrap();
1099 let variant = adt.variant_of_res(res);
1100 let mut failed_fields = vec![];
1101 for field in fields {
1102 let (hir_id, use_ctxt) = (field.hir_id, field.ident.span);
1103 let index = self.typeck_results().field_index(field.hir_id);
1104 if self.check_field(hir_id, use_ctxt, adt, &variant.fields[index]) {
1105 failed_fields.push((field.ident.name, field.ident.span, true));
1106 }
1107 }
1108 self.emit_unreachable_field_error(failed_fields, adt, None, qpath.span());
1109 }
1110
1111 intravisit::walk_pat(self, pat);
1112 }
1113}
1114
1115struct TypePrivacyVisitor<'tcx> {
1122 tcx: TyCtxt<'tcx>,
1123 module_def_id: LocalModDefId,
1124 maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
1125 span: Span,
1126}
1127
1128impl<'tcx> TypePrivacyVisitor<'tcx> {
1129 fn item_is_accessible(&self, did: DefId) -> bool {
1130 self.tcx.visibility(did).is_accessible_from(self.module_def_id, self.tcx)
1131 }
1132
1133 fn check_expr_pat_type(&mut self, id: hir::HirId, span: Span) -> bool {
1135 self.span = span;
1136 let typeck_results = self
1137 .maybe_typeck_results
1138 .unwrap_or_else(|| span_bug!(span, "`hir::Expr` or `hir::Pat` outside of a body"));
1139 let result: ControlFlow<()> = try {
1140 self.visit(typeck_results.node_type(id))?;
1141 self.visit(typeck_results.node_args(id))?;
1142 if let Some(adjustments) = typeck_results.adjustments().get(id) {
1143 adjustments.iter().try_for_each(|adjustment| self.visit(adjustment.target))?;
1144 }
1145 };
1146 result.is_break()
1147 }
1148
1149 fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
1150 let is_error = !self.item_is_accessible(def_id);
1151 if is_error {
1152 self.tcx.dcx().emit_err(ItemIsPrivate { span: self.span, kind, descr: descr.into() });
1153 }
1154 is_error
1155 }
1156}
1157
1158impl<'tcx> rustc_ty_utils::sig_types::SpannedTypeVisitor<'tcx> for TypePrivacyVisitor<'tcx> {
1159 type Result = ControlFlow<()>;
1160 fn visit(&mut self, span: Span, value: impl TypeVisitable<TyCtxt<'tcx>>) -> Self::Result {
1161 self.span = span;
1162 value.visit_with(&mut self.skeleton())
1163 }
1164}
1165
1166impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
1167 fn visit_nested_body(&mut self, body_id: hir::BodyId) {
1168 let old_maybe_typeck_results =
1169 self.maybe_typeck_results.replace(self.tcx.typeck_body(body_id));
1170 self.visit_body(self.tcx.hir_body(body_id));
1171 self.maybe_typeck_results = old_maybe_typeck_results;
1172 }
1173
1174 fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
1175 self.span = hir_ty.span;
1176 if self
1177 .visit(
1178 self.maybe_typeck_results
1179 .unwrap_or_else(|| span_bug!(hir_ty.span, "`hir::Ty` outside of a body"))
1180 .node_type(hir_ty.hir_id),
1181 )
1182 .is_break()
1183 {
1184 return;
1185 }
1186
1187 intravisit::walk_ty(self, hir_ty);
1188 }
1189
1190 fn visit_infer(
1191 &mut self,
1192 inf_id: rustc_hir::HirId,
1193 inf_span: Span,
1194 _kind: InferKind<'tcx>,
1195 ) -> Self::Result {
1196 self.span = inf_span;
1197 if let Some(ty) = self
1198 .maybe_typeck_results
1199 .unwrap_or_else(|| span_bug!(inf_span, "Inference variable outside of a body"))
1200 .node_type_opt(inf_id)
1201 {
1202 if self.visit(ty).is_break() {
1203 return;
1204 }
1205 } else {
1206 }
1208
1209 self.visit_id(inf_id)
1210 }
1211
1212 fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
1214 if self.check_expr_pat_type(expr.hir_id, expr.span) {
1215 return;
1217 }
1218 match expr.kind {
1219 hir::ExprKind::Assign(_, rhs, _) | hir::ExprKind::Match(rhs, ..) => {
1220 if self.check_expr_pat_type(rhs.hir_id, rhs.span) {
1222 return;
1223 }
1224 }
1225 hir::ExprKind::MethodCall(segment, ..) => {
1226 self.span = segment.ident.span;
1228 let typeck_results = self
1229 .maybe_typeck_results
1230 .unwrap_or_else(|| span_bug!(self.span, "`hir::Expr` outside of a body"));
1231 if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) {
1232 if self.visit(self.tcx.type_of(def_id).instantiate_identity()).is_break() {
1233 return;
1234 }
1235 } else {
1236 self.tcx
1237 .dcx()
1238 .span_delayed_bug(expr.span, "no type-dependent def for method call");
1239 }
1240 }
1241 _ => {}
1242 }
1243
1244 intravisit::walk_expr(self, expr);
1245 }
1246
1247 fn visit_qpath(&mut self, qpath: &'tcx hir::QPath<'tcx>, id: hir::HirId, span: Span) {
1254 let def = match qpath {
1255 hir::QPath::Resolved(_, path) => match path.res {
1256 Res::Def(kind, def_id) => Some((kind, def_id)),
1257 _ => None,
1258 },
1259 hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => {
1260 match self.maybe_typeck_results {
1261 Some(typeck_results) => typeck_results.type_dependent_def(id),
1262 None => None,
1264 }
1265 }
1266 };
1267 let def = def.filter(|(kind, _)| {
1268 matches!(
1269 kind,
1270 DefKind::AssocFn | DefKind::AssocConst | DefKind::AssocTy | DefKind::Static { .. }
1271 )
1272 });
1273 if let Some((kind, def_id)) = def {
1274 let is_local_static =
1275 if let DefKind::Static { .. } = kind { def_id.is_local() } else { false };
1276 if !self.item_is_accessible(def_id) && !is_local_static {
1277 let name = match *qpath {
1278 hir::QPath::LangItem(it, ..) => {
1279 self.tcx.lang_items().get(it).map(|did| self.tcx.def_path_str(did))
1280 }
1281 hir::QPath::Resolved(_, path) => Some(self.tcx.def_path_str(path.res.def_id())),
1282 hir::QPath::TypeRelative(_, segment) => Some(segment.ident.to_string()),
1283 };
1284 let kind = self.tcx.def_descr(def_id);
1285 let sess = self.tcx.sess;
1286 let _ = match name {
1287 Some(name) => {
1288 sess.dcx().emit_err(ItemIsPrivate { span, kind, descr: (&name).into() })
1289 }
1290 None => sess.dcx().emit_err(UnnamedItemIsPrivate { span, kind }),
1291 };
1292 return;
1293 }
1294 }
1295
1296 intravisit::walk_qpath(self, qpath, id);
1297 }
1298
1299 fn visit_pat(&mut self, pattern: &'tcx hir::Pat<'tcx>) {
1301 if self.check_expr_pat_type(pattern.hir_id, pattern.span) {
1302 return;
1304 }
1305
1306 intravisit::walk_pat(self, pattern);
1307 }
1308
1309 fn visit_local(&mut self, local: &'tcx hir::LetStmt<'tcx>) {
1310 if let Some(init) = local.init {
1311 if self.check_expr_pat_type(init.hir_id, init.span) {
1312 return;
1314 }
1315 }
1316
1317 intravisit::walk_local(self, local);
1318 }
1319}
1320
1321impl<'tcx> DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> {
1322 type Result = ControlFlow<()>;
1323 fn tcx(&self) -> TyCtxt<'tcx> {
1324 self.tcx
1325 }
1326 fn visit_def_id(
1327 &mut self,
1328 def_id: DefId,
1329 kind: &str,
1330 descr: &dyn fmt::Display,
1331 ) -> Self::Result {
1332 if self.check_def_id(def_id, kind, descr) {
1333 ControlFlow::Break(())
1334 } else {
1335 ControlFlow::Continue(())
1336 }
1337 }
1338}
1339
1340struct SearchInterfaceForPrivateItemsVisitor<'tcx> {
1348 tcx: TyCtxt<'tcx>,
1349 item_def_id: LocalDefId,
1350 required_visibility: ty::Visibility,
1352 required_effective_vis: Option<EffectiveVisibility>,
1353 in_assoc_ty: bool,
1354 in_primary_interface: bool,
1355}
1356
1357impl SearchInterfaceForPrivateItemsVisitor<'_> {
1358 fn generics(&mut self) -> &mut Self {
1359 self.in_primary_interface = true;
1360 for param in &self.tcx.generics_of(self.item_def_id).own_params {
1361 match param.kind {
1362 GenericParamDefKind::Lifetime => {}
1363 GenericParamDefKind::Type { has_default, .. } => {
1364 if has_default {
1365 let _ = self.visit(self.tcx.type_of(param.def_id).instantiate_identity());
1366 }
1367 }
1368 GenericParamDefKind::Const { .. } => {
1370 let _ = self.visit(self.tcx.type_of(param.def_id).instantiate_identity());
1371 }
1372 }
1373 }
1374 self
1375 }
1376
1377 fn predicates(&mut self) -> &mut Self {
1378 self.in_primary_interface = false;
1379 let _ = self.visit_predicates(self.tcx.explicit_predicates_of(self.item_def_id));
1386 self
1387 }
1388
1389 fn bounds(&mut self) -> &mut Self {
1390 self.in_primary_interface = false;
1391 let _ = self.visit_clauses(self.tcx.explicit_item_bounds(self.item_def_id).skip_binder());
1392 self
1393 }
1394
1395 fn ty(&mut self) -> &mut Self {
1396 self.in_primary_interface = true;
1397 let _ = self.visit(self.tcx.type_of(self.item_def_id).instantiate_identity());
1398 self
1399 }
1400
1401 fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
1402 if self.leaks_private_dep(def_id) {
1403 self.tcx.emit_node_span_lint(
1404 lint::builtin::EXPORTED_PRIVATE_DEPENDENCIES,
1405 self.tcx.local_def_id_to_hir_id(self.item_def_id),
1406 self.tcx.def_span(self.item_def_id.to_def_id()),
1407 FromPrivateDependencyInPublicInterface {
1408 kind,
1409 descr: descr.into(),
1410 krate: self.tcx.crate_name(def_id.krate),
1411 },
1412 );
1413 }
1414
1415 let Some(local_def_id) = def_id.as_local() else {
1416 return false;
1417 };
1418
1419 let vis = self.tcx.local_visibility(local_def_id);
1420 let span = self.tcx.def_span(self.item_def_id.to_def_id());
1421 let vis_span = self.tcx.def_span(def_id);
1422 if self.in_assoc_ty && !vis.is_at_least(self.required_visibility, self.tcx) {
1423 let vis_descr = match vis {
1424 ty::Visibility::Public => "public",
1425 ty::Visibility::Restricted(vis_def_id) => {
1426 if vis_def_id
1427 == self.tcx.parent_module_from_def_id(local_def_id).to_local_def_id()
1428 {
1429 "private"
1430 } else if vis_def_id.is_top_level_module() {
1431 "crate-private"
1432 } else {
1433 "restricted"
1434 }
1435 }
1436 };
1437
1438 self.tcx.dcx().emit_err(InPublicInterface {
1439 span,
1440 vis_descr,
1441 kind,
1442 descr: descr.into(),
1443 vis_span,
1444 });
1445 return false;
1446 }
1447
1448 let Some(effective_vis) = self.required_effective_vis else {
1449 return false;
1450 };
1451
1452 let reachable_at_vis = *effective_vis.at_level(Level::Reachable);
1453
1454 if !vis.is_at_least(reachable_at_vis, self.tcx) {
1455 let lint = if self.in_primary_interface {
1456 lint::builtin::PRIVATE_INTERFACES
1457 } else {
1458 lint::builtin::PRIVATE_BOUNDS
1459 };
1460 self.tcx.emit_node_span_lint(
1461 lint,
1462 self.tcx.local_def_id_to_hir_id(self.item_def_id),
1463 span,
1464 PrivateInterfacesOrBoundsLint {
1465 item_span: span,
1466 item_kind: self.tcx.def_descr(self.item_def_id.to_def_id()),
1467 item_descr: (&LazyDefPathStr {
1468 def_id: self.item_def_id.to_def_id(),
1469 tcx: self.tcx,
1470 })
1471 .into(),
1472 item_vis_descr: &reachable_at_vis.to_string(self.item_def_id, self.tcx),
1473 ty_span: vis_span,
1474 ty_kind: kind,
1475 ty_descr: descr.into(),
1476 ty_vis_descr: &vis.to_string(local_def_id, self.tcx),
1477 },
1478 );
1479 }
1480
1481 false
1482 }
1483
1484 fn leaks_private_dep(&self, item_id: DefId) -> bool {
1489 let ret = self.required_visibility.is_public() && self.tcx.is_private_dep(item_id.krate);
1490
1491 debug!("leaks_private_dep(item_id={:?})={}", item_id, ret);
1492 ret
1493 }
1494}
1495
1496impl<'tcx> DefIdVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'tcx> {
1497 type Result = ControlFlow<()>;
1498 fn tcx(&self) -> TyCtxt<'tcx> {
1499 self.tcx
1500 }
1501 fn visit_def_id(
1502 &mut self,
1503 def_id: DefId,
1504 kind: &str,
1505 descr: &dyn fmt::Display,
1506 ) -> Self::Result {
1507 if self.check_def_id(def_id, kind, descr) {
1508 ControlFlow::Break(())
1509 } else {
1510 ControlFlow::Continue(())
1511 }
1512 }
1513}
1514
1515struct PrivateItemsInPublicInterfacesChecker<'a, 'tcx> {
1516 tcx: TyCtxt<'tcx>,
1517 effective_visibilities: &'a EffectiveVisibilities,
1518}
1519
1520impl<'tcx> PrivateItemsInPublicInterfacesChecker<'_, 'tcx> {
1521 fn check(
1522 &self,
1523 def_id: LocalDefId,
1524 required_visibility: ty::Visibility,
1525 required_effective_vis: Option<EffectiveVisibility>,
1526 ) -> SearchInterfaceForPrivateItemsVisitor<'tcx> {
1527 SearchInterfaceForPrivateItemsVisitor {
1528 tcx: self.tcx,
1529 item_def_id: def_id,
1530 required_visibility,
1531 required_effective_vis,
1532 in_assoc_ty: false,
1533 in_primary_interface: true,
1534 }
1535 }
1536
1537 fn check_unnameable(&self, def_id: LocalDefId, effective_vis: Option<EffectiveVisibility>) {
1538 let Some(effective_vis) = effective_vis else {
1539 return;
1540 };
1541
1542 let reexported_at_vis = effective_vis.at_level(Level::Reexported);
1543 let reachable_at_vis = effective_vis.at_level(Level::Reachable);
1544
1545 if reachable_at_vis.is_public() && reexported_at_vis != reachable_at_vis {
1546 let hir_id = self.tcx.local_def_id_to_hir_id(def_id);
1547 let span = self.tcx.def_span(def_id.to_def_id());
1548 self.tcx.emit_node_span_lint(
1549 lint::builtin::UNNAMEABLE_TYPES,
1550 hir_id,
1551 span,
1552 UnnameableTypesLint {
1553 span,
1554 kind: self.tcx.def_descr(def_id.to_def_id()),
1555 descr: (&LazyDefPathStr { def_id: def_id.to_def_id(), tcx: self.tcx }).into(),
1556 reachable_vis: &reachable_at_vis.to_string(def_id, self.tcx),
1557 reexported_vis: &reexported_at_vis.to_string(def_id, self.tcx),
1558 },
1559 );
1560 }
1561 }
1562
1563 fn check_assoc_item(
1564 &self,
1565 def_id: LocalDefId,
1566 assoc_item_kind: AssocItemKind,
1567 vis: ty::Visibility,
1568 effective_vis: Option<EffectiveVisibility>,
1569 ) {
1570 let mut check = self.check(def_id, vis, effective_vis);
1571
1572 let (check_ty, is_assoc_ty) = match assoc_item_kind {
1573 AssocItemKind::Const | AssocItemKind::Fn { .. } => (true, false),
1574 AssocItemKind::Type => (self.tcx.defaultness(def_id).has_value(), true),
1575 };
1576
1577 check.in_assoc_ty = is_assoc_ty;
1578 check.generics().predicates();
1579 if check_ty {
1580 check.ty();
1581 }
1582 }
1583
1584 fn get(&self, def_id: LocalDefId) -> Option<EffectiveVisibility> {
1585 self.effective_visibilities.effective_vis(def_id).copied()
1586 }
1587
1588 fn check_item(&mut self, id: ItemId) {
1589 let tcx = self.tcx;
1590 let def_id = id.owner_id.def_id;
1591 let item_visibility = tcx.local_visibility(def_id);
1592 let effective_vis = self.get(def_id);
1593 let def_kind = tcx.def_kind(def_id);
1594
1595 match def_kind {
1596 DefKind::Const | DefKind::Static { .. } | DefKind::Fn | DefKind::TyAlias => {
1597 if let DefKind::TyAlias = def_kind {
1598 self.check_unnameable(def_id, effective_vis);
1599 }
1600 self.check(def_id, item_visibility, effective_vis).generics().predicates().ty();
1601 }
1602 DefKind::OpaqueTy => {
1603 self.check(def_id, item_visibility, effective_vis).generics().bounds();
1606 }
1607 DefKind::Trait => {
1608 let item = tcx.hir_item(id);
1609 if let hir::ItemKind::Trait(.., trait_item_refs) = item.kind {
1610 self.check_unnameable(item.owner_id.def_id, effective_vis);
1611
1612 self.check(item.owner_id.def_id, item_visibility, effective_vis)
1613 .generics()
1614 .predicates();
1615
1616 for trait_item_ref in trait_item_refs {
1617 self.check_assoc_item(
1618 trait_item_ref.id.owner_id.def_id,
1619 trait_item_ref.kind,
1620 item_visibility,
1621 effective_vis,
1622 );
1623
1624 if let AssocItemKind::Type = trait_item_ref.kind {
1625 self.check(
1626 trait_item_ref.id.owner_id.def_id,
1627 item_visibility,
1628 effective_vis,
1629 )
1630 .bounds();
1631 }
1632 }
1633 }
1634 }
1635 DefKind::TraitAlias => {
1636 self.check(def_id, item_visibility, effective_vis).generics().predicates();
1637 }
1638 DefKind::Enum => {
1639 let item = tcx.hir_item(id);
1640 if let hir::ItemKind::Enum(_, ref def, _) = item.kind {
1641 self.check_unnameable(item.owner_id.def_id, effective_vis);
1642
1643 self.check(item.owner_id.def_id, item_visibility, effective_vis)
1644 .generics()
1645 .predicates();
1646
1647 for variant in def.variants {
1648 for field in variant.data.fields() {
1649 self.check(field.def_id, item_visibility, effective_vis).ty();
1650 }
1651 }
1652 }
1653 }
1654 DefKind::ForeignMod => {
1656 let item = tcx.hir_item(id);
1657 if let hir::ItemKind::ForeignMod { items, .. } = item.kind {
1658 for foreign_item in items {
1659 let foreign_item = tcx.hir_foreign_item(foreign_item.id);
1660
1661 let ev = self.get(foreign_item.owner_id.def_id);
1662 let vis = tcx.local_visibility(foreign_item.owner_id.def_id);
1663
1664 if let ForeignItemKind::Type = foreign_item.kind {
1665 self.check_unnameable(foreign_item.owner_id.def_id, ev);
1666 }
1667
1668 self.check(foreign_item.owner_id.def_id, vis, ev)
1669 .generics()
1670 .predicates()
1671 .ty();
1672 }
1673 }
1674 }
1675 DefKind::Struct | DefKind::Union => {
1677 let item = tcx.hir_item(id);
1678 if let hir::ItemKind::Struct(_, ref struct_def, _)
1679 | hir::ItemKind::Union(_, ref struct_def, _) = item.kind
1680 {
1681 self.check_unnameable(item.owner_id.def_id, effective_vis);
1682 self.check(item.owner_id.def_id, item_visibility, effective_vis)
1683 .generics()
1684 .predicates();
1685
1686 for field in struct_def.fields() {
1687 let field_visibility = tcx.local_visibility(field.def_id);
1688 let field_ev = self.get(field.def_id);
1689
1690 self.check(
1691 field.def_id,
1692 min(item_visibility, field_visibility, tcx),
1693 field_ev,
1694 )
1695 .ty();
1696 }
1697 }
1698 }
1699 DefKind::Impl { .. } => {
1704 let item = tcx.hir_item(id);
1705 if let hir::ItemKind::Impl(impl_) = item.kind {
1706 let impl_vis = ty::Visibility::of_impl::<false>(
1707 item.owner_id.def_id,
1708 tcx,
1709 &Default::default(),
1710 );
1711
1712 let impl_ev = EffectiveVisibility::of_impl::<false>(
1724 item.owner_id.def_id,
1725 tcx,
1726 self.effective_visibilities,
1727 );
1728
1729 if impl_.of_trait.is_none() {
1732 self.check(item.owner_id.def_id, impl_vis, Some(impl_ev))
1733 .generics()
1734 .predicates();
1735 }
1736 for impl_item_ref in impl_.items {
1737 let impl_item_vis = if impl_.of_trait.is_none() {
1738 min(
1739 tcx.local_visibility(impl_item_ref.id.owner_id.def_id),
1740 impl_vis,
1741 tcx,
1742 )
1743 } else {
1744 impl_vis
1745 };
1746
1747 let impl_item_ev = if impl_.of_trait.is_none() {
1748 self.get(impl_item_ref.id.owner_id.def_id)
1749 .map(|ev| ev.min(impl_ev, self.tcx))
1750 } else {
1751 Some(impl_ev)
1752 };
1753
1754 self.check_assoc_item(
1755 impl_item_ref.id.owner_id.def_id,
1756 impl_item_ref.kind,
1757 impl_item_vis,
1758 impl_item_ev,
1759 );
1760 }
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}