1#![feature(associated_type_defaults)]
3#![feature(default_field_values)]
4#![feature(try_blocks)]
5mod errors;
8
9use std::fmt;
10use std::marker::PhantomData;
11use std::ops::ControlFlow;
12
13use errors::{
14 FieldIsPrivate, FieldIsPrivateLabel, FromPrivateDependencyInPublicInterface, InPublicInterface,
15 ItemIsPrivate, PrivateInterfacesOrBoundsLint, ReportEffectiveVisibility, UnnameableTypesLint,
16 UnnamedItemIsPrivate,
17};
18use rustc_ast::visit::{VisitorResult, try_visit};
19use rustc_data_structures::fx::FxHashSet;
20use rustc_data_structures::intern::Interned;
21use rustc_errors::{MultiSpan, listify};
22use rustc_hir as hir;
23use rustc_hir::def::{DefKind, Res};
24use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
25use rustc_hir::intravisit::{self, InferKind, Visitor};
26use rustc_hir::{AmbigArg, ForeignItemId, ItemId, OwnerId, PatKind, find_attr};
27use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, Level};
28use rustc_middle::query::Providers;
29use rustc_middle::ty::print::PrintTraitRefExt as _;
30use rustc_middle::ty::{
31 self, AssocContainer, Const, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable,
32 TypeVisitable, TypeVisitor,
33};
34use rustc_middle::{bug, span_bug};
35use rustc_session::lint;
36use rustc_span::{Ident, Span, Symbol, sym};
37use tracing::debug;
38
39struct LazyDefPathStr<'tcx> {
44 def_id: DefId,
45 tcx: TyCtxt<'tcx>,
46}
47
48impl<'tcx> fmt::Display for LazyDefPathStr<'tcx> {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 f.write_fmt(format_args!("{0}", self.tcx.def_path_str(self.def_id)))write!(f, "{}", self.tcx.def_path_str(self.def_id))
51 }
52}
53
54pub trait DefIdVisitor<'tcx> {
63 type Result: VisitorResult = ();
64 const SHALLOW: bool = false;
65 fn skip_assoc_tys(&self) -> bool {
66 false
67 }
68
69 fn tcx(&self) -> TyCtxt<'tcx>;
70 fn visit_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display)
74 -> Self::Result;
75
76 fn skeleton(&mut self) -> DefIdVisitorSkeleton<'_, 'tcx, Self> {
78 DefIdVisitorSkeleton {
79 def_id_visitor: self,
80 visited_tys: Default::default(),
81 dummy: Default::default(),
82 }
83 }
84 fn visit(&mut self, ty_fragment: impl TypeVisitable<TyCtxt<'tcx>>) -> Self::Result {
85 ty_fragment.visit_with(&mut self.skeleton())
86 }
87 fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> Self::Result {
88 self.skeleton().visit_trait(trait_ref)
89 }
90 fn visit_predicates(&mut self, predicates: ty::GenericPredicates<'tcx>) -> Self::Result {
91 self.skeleton().visit_clauses(predicates.predicates)
92 }
93 fn visit_clauses(&mut self, clauses: &[(ty::Clause<'tcx>, Span)]) -> Self::Result {
94 self.skeleton().visit_clauses(clauses)
95 }
96}
97
98pub struct DefIdVisitorSkeleton<'v, 'tcx, V: ?Sized> {
99 def_id_visitor: &'v mut V,
100 visited_tys: FxHashSet<Ty<'tcx>>,
101 dummy: PhantomData<TyCtxt<'tcx>>,
102}
103
104impl<'tcx, V> DefIdVisitorSkeleton<'_, 'tcx, V>
105where
106 V: DefIdVisitor<'tcx> + ?Sized,
107{
108 fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> V::Result {
109 let TraitRef { def_id, args, .. } = trait_ref;
110 match ::rustc_ast_ir::visit::VisitorResult::branch(self.def_id_visitor.visit_def_id(def_id,
"trait", &trait_ref.print_only_trait_path())) {
core::ops::ControlFlow::Continue(()) =>
(),
#[allow(unreachable_code)]
core::ops::ControlFlow::Break(r) => {
return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
}
};try_visit!(self.def_id_visitor.visit_def_id(
111 def_id,
112 "trait",
113 &trait_ref.print_only_trait_path()
114 ));
115 if V::SHALLOW { V::Result::output() } else { args.visit_with(self) }
116 }
117
118 fn visit_projection_term(&mut self, projection: ty::AliasTerm<'tcx>) -> V::Result {
119 let tcx = self.def_id_visitor.tcx();
120 let (trait_ref, assoc_args) = projection.trait_ref_and_own_args(tcx);
121 match ::rustc_ast_ir::visit::VisitorResult::branch(self.visit_trait(trait_ref))
{
core::ops::ControlFlow::Continue(()) =>
(),
#[allow(unreachable_code)]
core::ops::ControlFlow::Break(r) => {
return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
}
};try_visit!(self.visit_trait(trait_ref));
122 if V::SHALLOW {
123 V::Result::output()
124 } else {
125 V::Result::from_branch(
126 assoc_args.iter().try_for_each(|arg| arg.visit_with(self).branch()),
127 )
128 }
129 }
130
131 fn visit_clause(&mut self, clause: ty::Clause<'tcx>) -> V::Result {
132 match clause.kind().skip_binder() {
133 ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity: _ }) => {
134 self.visit_trait(trait_ref)
135 }
136 ty::ClauseKind::HostEffect(pred) => {
137 match ::rustc_ast_ir::visit::VisitorResult::branch(self.visit_trait(pred.trait_ref))
{
core::ops::ControlFlow::Continue(()) =>
(),
#[allow(unreachable_code)]
core::ops::ControlFlow::Break(r) => {
return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
}
};try_visit!(self.visit_trait(pred.trait_ref));
138 pred.constness.visit_with(self)
139 }
140 ty::ClauseKind::Projection(ty::ProjectionPredicate {
141 projection_term: projection_ty,
142 term,
143 }) => {
144 match ::rustc_ast_ir::visit::VisitorResult::branch(term.visit_with(self)) {
core::ops::ControlFlow::Continue(()) =>
(),
#[allow(unreachable_code)]
core::ops::ControlFlow::Break(r) => {
return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
}
};try_visit!(term.visit_with(self));
145 self.visit_projection_term(projection_ty)
146 }
147 ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, _region)) => ty.visit_with(self),
148 ty::ClauseKind::RegionOutlives(..) => V::Result::output(),
149 ty::ClauseKind::ConstArgHasType(ct, ty) => {
150 match ::rustc_ast_ir::visit::VisitorResult::branch(ct.visit_with(self)) {
core::ops::ControlFlow::Continue(()) =>
(),
#[allow(unreachable_code)]
core::ops::ControlFlow::Break(r) => {
return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
}
};try_visit!(ct.visit_with(self));
151 ty.visit_with(self)
152 }
153 ty::ClauseKind::ConstEvaluatable(ct) => ct.visit_with(self),
154 ty::ClauseKind::WellFormed(term) => term.visit_with(self),
155 ty::ClauseKind::UnstableFeature(_) => V::Result::output(),
156 }
157 }
158
159 fn visit_clauses(&mut self, clauses: &[(ty::Clause<'tcx>, Span)]) -> V::Result {
160 for &(clause, _) in clauses {
161 match ::rustc_ast_ir::visit::VisitorResult::branch(self.visit_clause(clause))
{
core::ops::ControlFlow::Continue(()) =>
(),
#[allow(unreachable_code)]
core::ops::ControlFlow::Break(r) => {
return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
}
};try_visit!(self.visit_clause(clause));
162 }
163 V::Result::output()
164 }
165}
166
167impl<'tcx, V> TypeVisitor<TyCtxt<'tcx>> for DefIdVisitorSkeleton<'_, 'tcx, V>
168where
169 V: DefIdVisitor<'tcx> + ?Sized,
170{
171 type Result = V::Result;
172
173 fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> Self::Result {
174 self.visit_clause(p.as_clause().unwrap())
175 }
176
177 fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
178 let tcx = self.def_id_visitor.tcx();
179 let ty_kind = *ty.kind();
182 match ty_kind {
183 ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), ..)
184 | ty::Foreign(def_id)
185 | ty::FnDef(def_id, ..)
186 | ty::Closure(def_id, ..)
187 | ty::CoroutineClosure(def_id, ..)
188 | ty::Coroutine(def_id, ..) => {
189 match ::rustc_ast_ir::visit::VisitorResult::branch(self.def_id_visitor.visit_def_id(def_id,
"type", &ty)) {
core::ops::ControlFlow::Continue(()) =>
(),
#[allow(unreachable_code)]
core::ops::ControlFlow::Break(r) => {
return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
}
};try_visit!(self.def_id_visitor.visit_def_id(def_id, "type", &ty));
190 if V::SHALLOW {
191 return V::Result::output();
192 }
193 if let ty::FnDef(..) = ty_kind {
197 match ::rustc_ast_ir::visit::VisitorResult::branch(tcx.fn_sig(def_id).instantiate_identity().skip_norm_wip().visit_with(self))
{
core::ops::ControlFlow::Continue(()) =>
(),
#[allow(unreachable_code)]
core::ops::ControlFlow::Break(r) => {
return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
}
};try_visit!(
199 tcx.fn_sig(def_id).instantiate_identity().skip_norm_wip().visit_with(self)
200 );
201 }
202 if let Some(assoc_item) = tcx.opt_associated_item(def_id)
207 && let Some(impl_def_id) = assoc_item.impl_container(tcx)
208 {
209 match ::rustc_ast_ir::visit::VisitorResult::branch(tcx.type_of(impl_def_id).instantiate_identity().skip_norm_wip().visit_with(self))
{
core::ops::ControlFlow::Continue(()) =>
(),
#[allow(unreachable_code)]
core::ops::ControlFlow::Break(r) => {
return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
}
};try_visit!(
210 tcx.type_of(impl_def_id)
211 .instantiate_identity()
212 .skip_norm_wip()
213 .visit_with(self)
214 );
215 }
216 }
217 ty::Alias(
218 data @ ty::AliasTy {
219 kind:
220 kind @ (ty::Inherent { def_id }
221 | ty::Free { def_id }
222 | ty::Projection { def_id }),
223 ..
224 },
225 ) => {
226 if self.def_id_visitor.skip_assoc_tys() {
227 return V::Result::output();
233 }
234 if !self.visited_tys.insert(ty) {
235 return V::Result::output();
239 }
240
241 match ::rustc_ast_ir::visit::VisitorResult::branch(self.def_id_visitor.visit_def_id(def_id,
match kind {
ty::Inherent { .. } | ty::Projection { .. } =>
"associated type",
ty::Free { .. } => "type alias",
ty::Opaque { .. } =>
::core::panicking::panic("internal error: entered unreachable code"),
}, &LazyDefPathStr { def_id, tcx })) {
core::ops::ControlFlow::Continue(()) =>
(),
#[allow(unreachable_code)]
core::ops::ControlFlow::Break(r) => {
return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
}
};try_visit!(self.def_id_visitor.visit_def_id(
242 def_id,
243 match kind {
244 ty::Inherent { .. } | ty::Projection { .. } => "associated type",
245 ty::Free { .. } => "type alias",
246 ty::Opaque { .. } => unreachable!(),
247 },
248 &LazyDefPathStr { def_id, tcx },
249 ));
250
251 return if V::SHALLOW {
253 V::Result::output()
254 } else if #[allow(non_exhaustive_omitted_patterns)] match kind {
ty::Projection { .. } => true,
_ => false,
}matches!(kind, ty::Projection { .. }) {
255 self.visit_projection_term(data.into())
256 } else {
257 V::Result::from_branch(
258 data.args.iter().try_for_each(|arg| arg.visit_with(self).branch()),
259 )
260 };
261 }
262 ty::Dynamic(predicates, ..) => {
263 for predicate in predicates {
266 let trait_ref = match predicate.skip_binder() {
267 ty::ExistentialPredicate::Trait(trait_ref) => trait_ref,
268 ty::ExistentialPredicate::Projection(proj) => proj.trait_ref(tcx),
269 ty::ExistentialPredicate::AutoTrait(def_id) => {
270 ty::ExistentialTraitRef::new(tcx, def_id, ty::GenericArgs::empty())
271 }
272 };
273 let ty::ExistentialTraitRef { def_id, .. } = trait_ref;
274 match ::rustc_ast_ir::visit::VisitorResult::branch(self.def_id_visitor.visit_def_id(def_id,
"trait", &trait_ref)) {
core::ops::ControlFlow::Continue(()) =>
(),
#[allow(unreachable_code)]
core::ops::ControlFlow::Break(r) => {
return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
}
};try_visit!(self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref));
275 }
276 }
277 ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, .. }) => {
278 if self.visited_tys.insert(ty) {
280 match ::rustc_ast_ir::visit::VisitorResult::branch(self.visit_clauses(tcx.explicit_item_bounds(def_id).skip_binder()))
{
core::ops::ControlFlow::Continue(()) =>
(),
#[allow(unreachable_code)]
core::ops::ControlFlow::Break(r) => {
return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
}
};try_visit!(self.visit_clauses(tcx.explicit_item_bounds(def_id).skip_binder()));
288 }
289 }
290 ty::Bool
293 | ty::Char
294 | ty::Int(..)
295 | ty::Uint(..)
296 | ty::Float(..)
297 | ty::Str
298 | ty::Never
299 | ty::Array(..)
300 | ty::Slice(..)
301 | ty::Tuple(..)
302 | ty::RawPtr(..)
303 | ty::Ref(..)
304 | ty::Pat(..)
305 | ty::FnPtr(..)
306 | ty::UnsafeBinder(_)
307 | ty::Param(..)
308 | ty::Bound(..)
309 | ty::Error(_)
310 | ty::CoroutineWitness(..) => {}
311 ty::Placeholder(..) | ty::Infer(..) => {
312 ::rustc_middle::util::bug::bug_fmt(format_args!("unexpected type: {0:?}", ty))bug!("unexpected type: {:?}", ty)
313 }
314 }
315
316 if V::SHALLOW { V::Result::output() } else { ty.super_visit_with(self) }
317 }
318
319 fn visit_const(&mut self, c: Const<'tcx>) -> Self::Result {
320 let tcx = self.def_id_visitor.tcx();
321 tcx.expand_abstract_consts(c).super_visit_with(self)
322 }
323}
324
325fn assoc_has_type_of(tcx: TyCtxt<'_>, item: &ty::AssocItem) -> bool {
326 if let ty::AssocKind::Type { data: ty::AssocTypeData::Normal(..) } = item.kind
327 && let hir::Node::TraitItem(item) =
328 tcx.hir_node(tcx.local_def_id_to_hir_id(item.def_id.expect_local()))
329 && let hir::TraitItemKind::Type(_, None) = item.kind
330 {
331 false
332 } else {
333 true
334 }
335}
336
337fn min(vis1: ty::Visibility, vis2: ty::Visibility, tcx: TyCtxt<'_>) -> ty::Visibility {
338 if vis1.greater_than(vis2, tcx) { vis2 } else { vis1 }
339}
340
341struct FindMin<'a, 'tcx, VL: VisibilityLike, const SHALLOW: bool> {
343 tcx: TyCtxt<'tcx>,
344 effective_visibilities: &'a EffectiveVisibilities,
345 min: VL,
346}
347
348impl<'a, 'tcx, VL: VisibilityLike, const SHALLOW: bool> DefIdVisitor<'tcx>
349 for FindMin<'a, 'tcx, VL, SHALLOW>
350{
351 const SHALLOW: bool = SHALLOW;
352 fn skip_assoc_tys(&self) -> bool {
353 true
354 }
355 fn tcx(&self) -> TyCtxt<'tcx> {
356 self.tcx
357 }
358 fn visit_def_id(&mut self, def_id: DefId, _kind: &str, _descr: &dyn fmt::Display) {
359 if let Some(def_id) = def_id.as_local() {
360 self.min = VL::new_min(self, def_id);
361 }
362 }
363}
364
365trait VisibilityLike: Sized {
366 const MAX: Self;
367 fn new_min<const SHALLOW: bool>(
368 find: &FindMin<'_, '_, Self, SHALLOW>,
369 def_id: LocalDefId,
370 ) -> Self;
371
372 fn of_impl<const SHALLOW: bool>(
375 def_id: LocalDefId,
376 of_trait: bool,
377 tcx: TyCtxt<'_>,
378 effective_visibilities: &EffectiveVisibilities,
379 ) -> Self {
380 let mut find = FindMin::<_, SHALLOW> { tcx, effective_visibilities, min: Self::MAX };
381 find.visit(tcx.type_of(def_id).instantiate_identity().skip_norm_wip());
382 if of_trait {
383 find.visit_trait(tcx.impl_trait_ref(def_id).instantiate_identity().skip_norm_wip());
384 }
385 find.min
386 }
387}
388
389impl VisibilityLike for ty::Visibility {
390 const MAX: Self = ty::Visibility::Public;
391 fn new_min<const SHALLOW: bool>(
392 find: &FindMin<'_, '_, Self, SHALLOW>,
393 def_id: LocalDefId,
394 ) -> Self {
395 min(find.tcx.local_visibility(def_id), find.min, find.tcx)
396 }
397}
398
399impl VisibilityLike for EffectiveVisibility {
400 const MAX: Self = EffectiveVisibility::from_vis(ty::Visibility::Public);
401 fn new_min<const SHALLOW: bool>(
402 find: &FindMin<'_, '_, Self, SHALLOW>,
403 def_id: LocalDefId,
404 ) -> Self {
405 let effective_vis =
406 find.effective_visibilities.effective_vis(def_id).copied().unwrap_or_else(|| {
407 let private_vis = ty::Visibility::Restricted(
408 find.tcx.parent_module_from_def_id(def_id).to_local_def_id(),
409 );
410 EffectiveVisibility::from_vis(private_vis)
411 });
412
413 effective_vis.min(find.min, find.tcx)
414 }
415}
416
417struct EmbargoVisitor<'tcx> {
419 tcx: TyCtxt<'tcx>,
420 effective_visibilities: EffectiveVisibilities,
422 changed: bool,
424}
425
426struct ReachEverythingInTheInterfaceVisitor<'a, 'tcx> {
427 effective_vis: EffectiveVisibility,
428 item_def_id: LocalDefId,
429 ev: &'a mut EmbargoVisitor<'tcx>,
430 level: Level,
431}
432
433impl<'tcx> EmbargoVisitor<'tcx> {
434 fn get(&self, def_id: LocalDefId) -> Option<EffectiveVisibility> {
435 self.effective_visibilities.effective_vis(def_id).copied()
436 }
437
438 fn update(
440 &mut self,
441 def_id: LocalDefId,
442 inherited_effective_vis: EffectiveVisibility,
443 level: Level,
444 ) {
445 let nominal_vis = self.tcx.local_visibility(def_id);
446 self.update_eff_vis(def_id, inherited_effective_vis, Some(nominal_vis), level);
447 }
448
449 fn update_eff_vis(
450 &mut self,
451 def_id: LocalDefId,
452 inherited_effective_vis: EffectiveVisibility,
453 max_vis: Option<ty::Visibility>,
454 level: Level,
455 ) {
456 let private_vis =
458 ty::Visibility::Restricted(self.tcx.parent_module_from_def_id(def_id).into());
459 if max_vis != Some(private_vis) {
460 self.changed |= self.effective_visibilities.update(
461 def_id,
462 max_vis,
463 private_vis,
464 inherited_effective_vis,
465 level,
466 self.tcx,
467 );
468 }
469 }
470
471 fn reach(
472 &mut self,
473 def_id: LocalDefId,
474 effective_vis: EffectiveVisibility,
475 ) -> ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
476 ReachEverythingInTheInterfaceVisitor {
477 effective_vis,
478 item_def_id: def_id,
479 ev: self,
480 level: Level::Reachable,
481 }
482 }
483
484 fn reach_through_impl_trait(
485 &mut self,
486 def_id: LocalDefId,
487 effective_vis: EffectiveVisibility,
488 ) -> ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
489 ReachEverythingInTheInterfaceVisitor {
490 effective_vis,
491 item_def_id: def_id,
492 ev: self,
493 level: Level::ReachableThroughImplTrait,
494 }
495 }
496}
497
498impl<'tcx> EmbargoVisitor<'tcx> {
499 fn check_assoc_item(&mut self, item: &ty::AssocItem, item_ev: EffectiveVisibility) {
500 let def_id = item.def_id.expect_local();
501 let tcx = self.tcx;
502 let mut reach = self.reach(def_id, item_ev);
503 reach.generics().predicates();
504 if assoc_has_type_of(tcx, item) {
505 reach.ty();
506 }
507 if item.is_type() && item.container == AssocContainer::Trait {
508 reach.bounds();
509 }
510 }
511
512 fn check_def_id(&mut self, owner_id: OwnerId) {
513 let item_ev = self.get(owner_id.def_id);
516 match self.tcx.def_kind(owner_id) {
517 DefKind::Use | DefKind::ExternCrate | DefKind::GlobalAsm => {}
519 DefKind::Mod => {}
521 DefKind::Macro { .. } => {}
523 DefKind::ForeignTy
524 | DefKind::Const { .. }
525 | DefKind::Static { .. }
526 | DefKind::Fn
527 | DefKind::TyAlias => {
528 if let Some(item_ev) = item_ev {
529 self.reach(owner_id.def_id, item_ev).generics().predicates().ty();
530 }
531 }
532 DefKind::Trait => {
533 if let Some(item_ev) = item_ev {
534 self.reach(owner_id.def_id, item_ev).generics().predicates();
535
536 for assoc_item in self.tcx.associated_items(owner_id).in_definition_order() {
537 let def_id = assoc_item.def_id.expect_local();
538 self.update(def_id, item_ev, Level::Reachable);
539
540 self.check_assoc_item(assoc_item, item_ev);
541 }
542 }
543 }
544 DefKind::TraitAlias => {
545 if let Some(item_ev) = item_ev {
546 self.reach(owner_id.def_id, item_ev).generics().predicates();
547 }
548 }
549 DefKind::Impl { of_trait } => {
550 let item_ev = EffectiveVisibility::of_impl::<true>(
561 owner_id.def_id,
562 of_trait,
563 self.tcx,
564 &self.effective_visibilities,
565 );
566
567 self.update_eff_vis(owner_id.def_id, item_ev, None, Level::Direct);
568
569 {
570 let mut reach = self.reach(owner_id.def_id, item_ev);
571 reach.generics().predicates().ty();
572 if of_trait {
573 reach.trait_ref();
574 }
575 }
576
577 for assoc_item in self.tcx.associated_items(owner_id).in_definition_order() {
578 let def_id = assoc_item.def_id.expect_local();
579 let max_vis =
580 if of_trait { None } else { Some(self.tcx.local_visibility(def_id)) };
581 self.update_eff_vis(def_id, item_ev, max_vis, Level::Direct);
582
583 if let Some(impl_item_ev) = self.get(def_id) {
584 self.check_assoc_item(assoc_item, impl_item_ev);
585 }
586 }
587 }
588 DefKind::Enum => {
589 if let Some(item_ev) = item_ev {
590 self.reach(owner_id.def_id, item_ev).generics().predicates();
591 }
592 let def = self.tcx.adt_def(owner_id);
593 for variant in def.variants() {
594 if let Some(item_ev) = item_ev {
595 self.update(variant.def_id.expect_local(), item_ev, Level::Reachable);
596 }
597
598 if let Some(variant_ev) = self.get(variant.def_id.expect_local()) {
599 if let Some(ctor_def_id) = variant.ctor_def_id() {
600 self.update(ctor_def_id.expect_local(), variant_ev, Level::Reachable);
601 }
602
603 for field in &variant.fields {
604 let field = field.did.expect_local();
605 self.update(field, variant_ev, Level::Reachable);
606 self.reach(field, variant_ev).ty();
607 }
608 self.reach(owner_id.def_id, variant_ev).ty();
611 }
612 if let Some(ctor_def_id) = variant.ctor_def_id() {
613 if let Some(ctor_ev) = self.get(ctor_def_id.expect_local()) {
614 self.reach(owner_id.def_id, ctor_ev).ty();
615 }
616 }
617 }
618 }
619 DefKind::Struct | DefKind::Union => {
620 let def = self.tcx.adt_def(owner_id).non_enum_variant();
621 if let Some(item_ev) = item_ev {
622 self.reach(owner_id.def_id, item_ev).generics().predicates();
623 for field in &def.fields {
624 let field = field.did.expect_local();
625 self.update(field, item_ev, Level::Reachable);
626 if let Some(field_ev) = self.get(field) {
627 self.reach(field, field_ev).ty();
628 }
629 }
630 }
631 if let Some(ctor_def_id) = def.ctor_def_id() {
632 if let Some(item_ev) = item_ev {
633 self.update(ctor_def_id.expect_local(), item_ev, Level::Reachable);
634 }
635 if let Some(ctor_ev) = self.get(ctor_def_id.expect_local()) {
636 self.reach(owner_id.def_id, ctor_ev).ty();
637 }
638 }
639 }
640 DefKind::ForeignMod => {}
642 DefKind::Field
643 | DefKind::Variant
644 | DefKind::AssocFn
645 | DefKind::AssocTy
646 | DefKind::AssocConst { .. }
647 | DefKind::TyParam
648 | DefKind::AnonConst
649 | DefKind::InlineConst
650 | DefKind::OpaqueTy
651 | DefKind::Closure
652 | DefKind::SyntheticCoroutineBody
653 | DefKind::ConstParam
654 | DefKind::LifetimeParam
655 | DefKind::Ctor(..) => {
656 ::rustc_middle::util::bug::bug_fmt(format_args!("should be checked while checking parent"))bug!("should be checked while checking parent")
657 }
658 }
659 }
660}
661
662impl ReachEverythingInTheInterfaceVisitor<'_, '_> {
663 fn generics(&mut self) -> &mut Self {
664 for param in &self.ev.tcx.generics_of(self.item_def_id).own_params {
665 if let GenericParamDefKind::Const { .. } = param.kind {
666 self.visit(
667 self.ev.tcx.type_of(param.def_id).instantiate_identity().skip_norm_wip(),
668 );
669 }
670 if let Some(default) = param.default_value(self.ev.tcx) {
671 self.visit(default.instantiate_identity().skip_norm_wip());
672 }
673 }
674 self
675 }
676
677 fn predicates(&mut self) -> &mut Self {
678 self.visit_predicates(self.ev.tcx.explicit_predicates_of(self.item_def_id));
679 self
680 }
681
682 fn bounds(&mut self) -> &mut Self {
683 self.visit_clauses(self.ev.tcx.explicit_item_bounds(self.item_def_id).skip_binder());
684 self
685 }
686
687 fn ty(&mut self) -> &mut Self {
688 self.visit(self.ev.tcx.type_of(self.item_def_id).instantiate_identity().skip_norm_wip());
689 self
690 }
691
692 fn trait_ref(&mut self) -> &mut Self {
693 self.visit_trait(
694 self.ev.tcx.impl_trait_ref(self.item_def_id).instantiate_identity().skip_norm_wip(),
695 );
696 self
697 }
698}
699
700impl<'tcx> DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
701 fn tcx(&self) -> TyCtxt<'tcx> {
702 self.ev.tcx
703 }
704 fn visit_def_id(&mut self, def_id: DefId, _kind: &str, _descr: &dyn fmt::Display) {
705 if let Some(def_id) = def_id.as_local() {
706 let max_vis = (self.level != Level::ReachableThroughImplTrait)
710 .then(|| self.ev.tcx.local_visibility(def_id));
711 self.ev.update_eff_vis(def_id, self.effective_vis, max_vis, self.level);
712 }
713 }
714}
715
716pub struct TestReachabilityVisitor<'a, 'tcx> {
718 tcx: TyCtxt<'tcx>,
719 effective_visibilities: &'a EffectiveVisibilities,
720}
721
722impl<'a, 'tcx> TestReachabilityVisitor<'a, 'tcx> {
723 fn effective_visibility_diagnostic(&self, def_id: LocalDefId) {
724 if {
{
'done:
{
for i in
::rustc_hir::attrs::HasAttrs::get_attrs(def_id, &self.tcx) {
#[allow(unused_imports)]
use rustc_hir::attrs::AttributeKind::*;
let i: &rustc_hir::Attribute = i;
match i {
rustc_hir::Attribute::Parsed(RustcEffectiveVisibility) => {
break 'done Some(());
}
rustc_hir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}.is_some()find_attr!(self.tcx, def_id, RustcEffectiveVisibility) {
725 let mut error_msg = String::new();
726 let span = self.tcx.def_span(def_id.to_def_id());
727 if let Some(effective_vis) = self.effective_visibilities.effective_vis(def_id) {
728 for level in Level::all_levels() {
729 let vis_str = effective_vis.at_level(level).to_string(def_id, self.tcx);
730 if level != Level::Direct {
731 error_msg.push_str(", ");
732 }
733 error_msg.push_str(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?}: {1}", level, vis_str))
})format!("{level:?}: {vis_str}"));
734 }
735 } else {
736 error_msg.push_str("not in the table");
737 }
738 self.tcx.dcx().emit_err(ReportEffectiveVisibility { span, descr: error_msg });
739 }
740 }
741}
742
743impl<'a, 'tcx> TestReachabilityVisitor<'a, 'tcx> {
744 fn check_def_id(&self, owner_id: OwnerId) {
745 self.effective_visibility_diagnostic(owner_id.def_id);
746
747 match self.tcx.def_kind(owner_id) {
748 DefKind::Enum => {
749 let def = self.tcx.adt_def(owner_id.def_id);
750 for variant in def.variants() {
751 self.effective_visibility_diagnostic(variant.def_id.expect_local());
752 if let Some(ctor_def_id) = variant.ctor_def_id() {
753 self.effective_visibility_diagnostic(ctor_def_id.expect_local());
754 }
755 for field in &variant.fields {
756 self.effective_visibility_diagnostic(field.did.expect_local());
757 }
758 }
759 }
760 DefKind::Struct | DefKind::Union => {
761 let def = self.tcx.adt_def(owner_id.def_id).non_enum_variant();
762 if let Some(ctor_def_id) = def.ctor_def_id() {
763 self.effective_visibility_diagnostic(ctor_def_id.expect_local());
764 }
765 for field in &def.fields {
766 self.effective_visibility_diagnostic(field.did.expect_local());
767 }
768 }
769 _ => {}
770 }
771 }
772}
773
774struct NamePrivacyVisitor<'tcx> {
780 tcx: TyCtxt<'tcx>,
781 maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
782}
783
784impl<'tcx> NamePrivacyVisitor<'tcx> {
785 #[track_caller]
789 fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> {
790 self.maybe_typeck_results
791 .expect("`NamePrivacyVisitor::typeck_results` called outside of body")
792 }
793
794 fn check_field(
796 &self,
797 hir_id: hir::HirId, use_ctxt: Span, def: ty::AdtDef<'tcx>, field: &'tcx ty::FieldDef,
801 ) -> bool {
802 if def.is_enum() {
803 return true;
804 }
805
806 let ident = Ident::new(sym::dummy, use_ctxt);
808 let (_, def_id) = self.tcx.adjust_ident_and_get_scope(ident, def.did(), hir_id);
809 !field.vis.is_accessible_from(def_id, self.tcx)
810 }
811
812 fn emit_unreachable_field_error(
814 &self,
815 fields: Vec<(Symbol, Span, bool )>,
816 def: ty::AdtDef<'tcx>, update_syntax: Option<Span>,
818 struct_span: Span,
819 ) {
820 if def.is_enum() || fields.is_empty() {
821 return;
822 }
823
824 let Some(field_names) = listify(&fields[..], |(n, _, _)| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}`", n))
})format!("`{n}`")) else { return };
836 let span: MultiSpan = fields.iter().map(|(_, span, _)| *span).collect::<Vec<Span>>().into();
837
838 let rest_field_names: Vec<_> =
840 fields.iter().filter(|(_, _, is_present)| !is_present).map(|(n, _, _)| n).collect();
841 let rest_len = rest_field_names.len();
842 let rest_field_names =
843 listify(&rest_field_names[..], |n| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}`", n))
})format!("`{n}`")).unwrap_or_default();
844 let labels = fields
846 .iter()
847 .filter(|(_, _, is_present)| *is_present)
848 .map(|(_, span, _)| FieldIsPrivateLabel::Other { span: *span })
849 .chain(update_syntax.iter().map(|span| FieldIsPrivateLabel::IsUpdateSyntax {
850 span: *span,
851 rest_field_names: rest_field_names.clone(),
852 rest_len,
853 }))
854 .collect();
855
856 self.tcx.dcx().emit_err(FieldIsPrivate {
857 span,
858 struct_span: if self
859 .tcx
860 .sess
861 .source_map()
862 .is_multiline(fields[0].1.between(struct_span))
863 {
864 Some(struct_span)
865 } else {
866 None
867 },
868 field_names,
869 variant_descr: def.variant_descr(),
870 def_path_str: self.tcx.def_path_str(def.did()),
871 labels,
872 len: fields.len(),
873 });
874 }
875
876 fn check_expanded_fields(
877 &self,
878 adt: ty::AdtDef<'tcx>,
879 variant: &'tcx ty::VariantDef,
880 fields: &[hir::ExprField<'tcx>],
881 hir_id: hir::HirId,
882 span: Span,
883 struct_span: Span,
884 ) {
885 let mut failed_fields = ::alloc::vec::Vec::new()vec![];
886 for (vf_index, variant_field) in variant.fields.iter_enumerated() {
887 let field =
888 fields.iter().find(|f| self.typeck_results().field_index(f.hir_id) == vf_index);
889 let (hir_id, use_ctxt, span) = match field {
890 Some(field) => (field.hir_id, field.ident.span, field.span),
891 None => (hir_id, span, span),
892 };
893 if self.check_field(hir_id, use_ctxt, adt, variant_field) {
894 let name = match field {
895 Some(field) => field.ident.name,
896 None => variant_field.name,
897 };
898 failed_fields.push((name, span, field.is_some()));
899 }
900 }
901 self.emit_unreachable_field_error(failed_fields, adt, Some(span), struct_span);
902 }
903}
904
905impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> {
906 fn visit_nested_body(&mut self, body_id: hir::BodyId) {
907 let new_typeck_results = self.tcx.typeck_body(body_id);
908 if new_typeck_results.tainted_by_errors.is_some() {
910 return;
911 }
912 let old_maybe_typeck_results = self.maybe_typeck_results.replace(new_typeck_results);
913 self.visit_body(self.tcx.hir_body(body_id));
914 self.maybe_typeck_results = old_maybe_typeck_results;
915 }
916
917 fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
918 if let hir::ExprKind::Struct(qpath, fields, ref base) = expr.kind {
919 let res = self.typeck_results().qpath_res(qpath, expr.hir_id);
920 let adt = self.typeck_results().expr_ty(expr).ty_adt_def().unwrap();
921 let variant = adt.variant_of_res(res);
922 match *base {
923 hir::StructTailExpr::Base(base) => {
924 self.check_expanded_fields(
928 adt,
929 variant,
930 fields,
931 base.hir_id,
932 base.span,
933 qpath.span(),
934 );
935 }
936 hir::StructTailExpr::DefaultFields(span) => {
937 self.check_expanded_fields(
938 adt,
939 variant,
940 fields,
941 expr.hir_id,
942 span,
943 qpath.span(),
944 );
945 }
946 hir::StructTailExpr::None | hir::StructTailExpr::NoneWithError(_) => {
947 let mut failed_fields = ::alloc::vec::Vec::new()vec![];
948 for field in fields {
949 let (hir_id, use_ctxt) = (field.hir_id, field.ident.span);
950 let index = self.typeck_results().field_index(field.hir_id);
951 if self.check_field(hir_id, use_ctxt, adt, &variant.fields[index]) {
952 failed_fields.push((field.ident.name, field.ident.span, true));
953 }
954 }
955 self.emit_unreachable_field_error(failed_fields, adt, None, qpath.span());
956 }
957 }
958 }
959
960 intravisit::walk_expr(self, expr);
961 }
962
963 fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) {
964 if let PatKind::Struct(ref qpath, fields, _) = pat.kind {
965 let res = self.typeck_results().qpath_res(qpath, pat.hir_id);
966 let adt = self.typeck_results().pat_ty(pat).ty_adt_def().unwrap();
967 let variant = adt.variant_of_res(res);
968 let mut failed_fields = ::alloc::vec::Vec::new()vec![];
969 for field in fields {
970 let (hir_id, use_ctxt) = (field.hir_id, field.ident.span);
971 let index = self.typeck_results().field_index(field.hir_id);
972 if self.check_field(hir_id, use_ctxt, adt, &variant.fields[index]) {
973 failed_fields.push((field.ident.name, field.ident.span, true));
974 }
975 }
976 self.emit_unreachable_field_error(failed_fields, adt, None, qpath.span());
977 }
978
979 intravisit::walk_pat(self, pat);
980 }
981}
982
983struct TypePrivacyVisitor<'tcx> {
988 tcx: TyCtxt<'tcx>,
989 module_def_id: LocalModDefId,
990 maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
991 span: Span,
992}
993
994impl<'tcx> TypePrivacyVisitor<'tcx> {
995 fn item_is_accessible(&self, did: DefId) -> bool {
996 self.tcx.visibility(did).is_accessible_from(self.module_def_id, self.tcx)
997 }
998
999 fn check_expr_pat_type(&mut self, id: hir::HirId, span: Span) -> bool {
1001 self.span = span;
1002 let typeck_results = self
1003 .maybe_typeck_results
1004 .unwrap_or_else(|| ::rustc_middle::util::bug::span_bug_fmt(span,
format_args!("`hir::Expr` or `hir::Pat` outside of a body"))span_bug!(span, "`hir::Expr` or `hir::Pat` outside of a body"));
1005 try {
1006 self.visit(typeck_results.node_type(id))?;
1007 self.visit(typeck_results.node_args(id))?;
1008 if let Some(adjustments) = typeck_results.adjustments().get(id) {
1009 adjustments.iter().try_for_each(|adjustment| self.visit(adjustment.target))?;
1010 }
1011 }
1012 .is_break()
1013 }
1014
1015 fn check_def_id(&self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
1016 let is_error = !self.item_is_accessible(def_id);
1017 if is_error {
1018 self.tcx.dcx().emit_err(ItemIsPrivate { span: self.span, kind, descr: descr.into() });
1019 }
1020 is_error
1021 }
1022}
1023
1024impl<'tcx> rustc_ty_utils::sig_types::SpannedTypeVisitor<'tcx> for TypePrivacyVisitor<'tcx> {
1025 type Result = ControlFlow<()>;
1026 fn visit(&mut self, span: Span, value: impl TypeVisitable<TyCtxt<'tcx>>) -> Self::Result {
1027 self.span = span;
1028 value.visit_with(&mut self.skeleton())
1029 }
1030}
1031
1032impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
1033 fn visit_nested_body(&mut self, body_id: hir::BodyId) {
1034 let old_maybe_typeck_results =
1035 self.maybe_typeck_results.replace(self.tcx.typeck_body(body_id));
1036 self.visit_body(self.tcx.hir_body(body_id));
1037 self.maybe_typeck_results = old_maybe_typeck_results;
1038 }
1039
1040 fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
1041 self.span = hir_ty.span;
1042 if self
1043 .visit(
1044 self.maybe_typeck_results
1045 .unwrap_or_else(|| ::rustc_middle::util::bug::span_bug_fmt(hir_ty.span,
format_args!("`hir::Ty` outside of a body"))span_bug!(hir_ty.span, "`hir::Ty` outside of a body"))
1046 .node_type(hir_ty.hir_id),
1047 )
1048 .is_break()
1049 {
1050 return;
1051 }
1052
1053 intravisit::walk_ty(self, hir_ty);
1054 }
1055
1056 fn visit_infer(
1057 &mut self,
1058 inf_id: rustc_hir::HirId,
1059 inf_span: Span,
1060 _kind: InferKind<'tcx>,
1061 ) -> Self::Result {
1062 self.span = inf_span;
1063 if let Some(ty) = self
1064 .maybe_typeck_results
1065 .unwrap_or_else(|| ::rustc_middle::util::bug::span_bug_fmt(inf_span,
format_args!("Inference variable outside of a body"))span_bug!(inf_span, "Inference variable outside of a body"))
1066 .node_type_opt(inf_id)
1067 {
1068 if self.visit(ty).is_break() {
1069 return;
1070 }
1071 } else {
1072 }
1074
1075 self.visit_id(inf_id)
1076 }
1077
1078 fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
1080 if self.check_expr_pat_type(expr.hir_id, expr.span) {
1081 return;
1083 }
1084 match expr.kind {
1085 hir::ExprKind::Assign(_, rhs, _) | hir::ExprKind::Match(rhs, ..) => {
1086 if self.check_expr_pat_type(rhs.hir_id, rhs.span) {
1088 return;
1089 }
1090 }
1091 hir::ExprKind::MethodCall(segment, ..) => {
1092 self.span = segment.ident.span;
1094 let typeck_results = self
1095 .maybe_typeck_results
1096 .unwrap_or_else(|| ::rustc_middle::util::bug::span_bug_fmt(self.span,
format_args!("`hir::Expr` outside of a body"))span_bug!(self.span, "`hir::Expr` outside of a body"));
1097 if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) {
1098 if self
1099 .visit(self.tcx.type_of(def_id).instantiate_identity().skip_norm_wip())
1100 .is_break()
1101 {
1102 return;
1103 }
1104 } else {
1105 self.tcx
1106 .dcx()
1107 .span_delayed_bug(expr.span, "no type-dependent def for method call");
1108 }
1109 }
1110 _ => {}
1111 }
1112
1113 intravisit::walk_expr(self, expr);
1114 }
1115
1116 fn visit_qpath(&mut self, qpath: &'tcx hir::QPath<'tcx>, id: hir::HirId, span: Span) {
1123 let def = match qpath {
1124 hir::QPath::Resolved(_, path) => match path.res {
1125 Res::Def(kind, def_id) => Some((kind, def_id)),
1126 _ => None,
1127 },
1128 hir::QPath::TypeRelative(..) => {
1129 match self.maybe_typeck_results {
1130 Some(typeck_results) => typeck_results.type_dependent_def(id),
1131 None => None,
1133 }
1134 }
1135 };
1136 let def = def.filter(|(kind, _)| {
1137 #[allow(non_exhaustive_omitted_patterns)] match kind {
DefKind::AssocFn | DefKind::AssocConst { .. } | DefKind::AssocTy |
DefKind::Static { .. } => true,
_ => false,
}matches!(
1138 kind,
1139 DefKind::AssocFn
1140 | DefKind::AssocConst { .. }
1141 | DefKind::AssocTy
1142 | DefKind::Static { .. }
1143 )
1144 });
1145 if let Some((kind, def_id)) = def {
1146 let is_local_static =
1147 if let DefKind::Static { .. } = kind { def_id.is_local() } else { false };
1148 if !self.item_is_accessible(def_id) && !is_local_static {
1149 let name = match *qpath {
1150 hir::QPath::Resolved(_, path) => Some(self.tcx.def_path_str(path.res.def_id())),
1151 hir::QPath::TypeRelative(_, segment) => Some(segment.ident.to_string()),
1152 };
1153 let kind = self.tcx.def_descr(def_id);
1154 let sess = self.tcx.sess;
1155 let _ = match name {
1156 Some(name) => {
1157 sess.dcx().emit_err(ItemIsPrivate { span, kind, descr: (&name).into() })
1158 }
1159 None => sess.dcx().emit_err(UnnamedItemIsPrivate { span, kind }),
1160 };
1161 return;
1162 }
1163 }
1164
1165 intravisit::walk_qpath(self, qpath, id);
1166 }
1167
1168 fn visit_pat(&mut self, pattern: &'tcx hir::Pat<'tcx>) {
1170 if self.check_expr_pat_type(pattern.hir_id, pattern.span) {
1171 return;
1173 }
1174
1175 intravisit::walk_pat(self, pattern);
1176 }
1177
1178 fn visit_local(&mut self, local: &'tcx hir::LetStmt<'tcx>) {
1179 if let Some(init) = local.init {
1180 if self.check_expr_pat_type(init.hir_id, init.span) {
1181 return;
1183 }
1184 }
1185
1186 intravisit::walk_local(self, local);
1187 }
1188}
1189
1190impl<'tcx> DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> {
1191 type Result = ControlFlow<()>;
1192 fn tcx(&self) -> TyCtxt<'tcx> {
1193 self.tcx
1194 }
1195 fn visit_def_id(
1196 &mut self,
1197 def_id: DefId,
1198 kind: &str,
1199 descr: &dyn fmt::Display,
1200 ) -> Self::Result {
1201 if self.check_def_id(def_id, kind, descr) {
1202 ControlFlow::Break(())
1203 } else {
1204 ControlFlow::Continue(())
1205 }
1206 }
1207}
1208
1209struct SearchInterfaceForPrivateItemsVisitor<'tcx> {
1215 tcx: TyCtxt<'tcx>,
1216 item_def_id: LocalDefId,
1217 required_visibility: ty::Visibility,
1219 required_effective_vis: Option<EffectiveVisibility>,
1220 hard_error: bool = false,
1221 in_primary_interface: bool = true,
1222 skip_assoc_tys: bool = false,
1223}
1224
1225impl SearchInterfaceForPrivateItemsVisitor<'_> {
1226 fn generics(&mut self) -> &mut Self {
1227 self.in_primary_interface = true;
1228 for param in &self.tcx.generics_of(self.item_def_id).own_params {
1229 if let GenericParamDefKind::Const { .. } = param.kind {
1230 let _ = self
1231 .visit(self.tcx.type_of(param.def_id).instantiate_identity().skip_norm_wip());
1232 }
1233 if let Some(default) = param.default_value(self.tcx) {
1234 let _ = self.visit(default.instantiate_identity().skip_norm_wip());
1235 }
1236 }
1237 self
1238 }
1239
1240 fn predicates(&mut self) -> &mut Self {
1241 self.in_primary_interface = false;
1242 let _ = self.visit_predicates(self.tcx.explicit_predicates_of(self.item_def_id));
1249 self
1250 }
1251
1252 fn bounds(&mut self) -> &mut Self {
1253 self.in_primary_interface = false;
1254 let _ = self.visit_clauses(self.tcx.explicit_item_bounds(self.item_def_id).skip_binder());
1255 self
1256 }
1257
1258 fn ty(&mut self) -> &mut Self {
1259 self.in_primary_interface = true;
1260 let _ =
1261 self.visit(self.tcx.type_of(self.item_def_id).instantiate_identity().skip_norm_wip());
1262 self
1263 }
1264
1265 fn trait_ref(&mut self) -> &mut Self {
1266 self.in_primary_interface = true;
1267 let _ = self.visit_trait(
1268 self.tcx.impl_trait_ref(self.item_def_id).instantiate_identity().skip_norm_wip(),
1269 );
1270 self
1271 }
1272
1273 fn check_def_id(&self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
1274 if self.leaks_private_dep(def_id) {
1275 self.tcx.emit_node_span_lint(
1276 lint::builtin::EXPORTED_PRIVATE_DEPENDENCIES,
1277 self.tcx.local_def_id_to_hir_id(self.item_def_id),
1278 self.tcx.def_span(self.item_def_id.to_def_id()),
1279 FromPrivateDependencyInPublicInterface {
1280 kind,
1281 descr: descr.into(),
1282 krate: self.tcx.crate_name(def_id.krate),
1283 },
1284 );
1285 }
1286
1287 let Some(local_def_id) = def_id.as_local() else {
1288 return false;
1289 };
1290
1291 let vis = self.tcx.local_visibility(local_def_id);
1292 if self.hard_error && self.required_visibility.greater_than(vis, self.tcx) {
1293 let vis_descr = match vis {
1294 ty::Visibility::Public => "public",
1295 ty::Visibility::Restricted(vis_def_id) => {
1296 if vis_def_id
1297 == self.tcx.parent_module_from_def_id(local_def_id).to_local_def_id()
1298 {
1299 "private"
1300 } else if vis_def_id.is_top_level_module() {
1301 "crate-private"
1302 } else {
1303 "restricted"
1304 }
1305 }
1306 };
1307
1308 let span = self.tcx.def_span(self.item_def_id.to_def_id());
1309 let vis_span = self.tcx.def_span(def_id);
1310 self.tcx.dcx().emit_err(InPublicInterface {
1311 span,
1312 vis_descr,
1313 kind,
1314 descr: descr.into(),
1315 vis_span,
1316 });
1317 return false;
1318 }
1319
1320 let Some(effective_vis) = self.required_effective_vis else {
1321 return false;
1322 };
1323
1324 let reachable_at_vis = *effective_vis.at_level(Level::Reachable);
1325
1326 if reachable_at_vis.greater_than(vis, self.tcx) {
1327 let lint = if self.in_primary_interface {
1328 lint::builtin::PRIVATE_INTERFACES
1329 } else {
1330 lint::builtin::PRIVATE_BOUNDS
1331 };
1332 let span = self.tcx.def_span(self.item_def_id.to_def_id());
1333 let vis_span = self.tcx.def_span(def_id);
1334 self.tcx.emit_node_span_lint(
1335 lint,
1336 self.tcx.local_def_id_to_hir_id(self.item_def_id),
1337 span,
1338 PrivateInterfacesOrBoundsLint {
1339 item_span: span,
1340 item_kind: self.tcx.def_descr(self.item_def_id.to_def_id()),
1341 item_descr: (&LazyDefPathStr {
1342 def_id: self.item_def_id.to_def_id(),
1343 tcx: self.tcx,
1344 })
1345 .into(),
1346 item_vis_descr: &reachable_at_vis.to_string(self.item_def_id, self.tcx),
1347 ty_span: vis_span,
1348 ty_kind: kind,
1349 ty_descr: descr.into(),
1350 ty_vis_descr: &vis.to_string(local_def_id, self.tcx),
1351 },
1352 );
1353 }
1354
1355 false
1356 }
1357
1358 fn leaks_private_dep(&self, item_id: DefId) -> bool {
1363 let ret = self.required_visibility.is_public() && self.tcx.is_private_dep(item_id.krate);
1364
1365 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_privacy/src/lib.rs:1365",
"rustc_privacy", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_privacy/src/lib.rs"),
::tracing_core::__macro_support::Option::Some(1365u32),
::tracing_core::__macro_support::Option::Some("rustc_privacy"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("leaks_private_dep(item_id={0:?})={1}",
item_id, ret) as &dyn Value))])
});
} else { ; }
};debug!("leaks_private_dep(item_id={:?})={}", item_id, ret);
1366 ret
1367 }
1368}
1369
1370impl<'tcx> DefIdVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'tcx> {
1371 type Result = ControlFlow<()>;
1372 fn skip_assoc_tys(&self) -> bool {
1373 self.skip_assoc_tys
1374 }
1375 fn tcx(&self) -> TyCtxt<'tcx> {
1376 self.tcx
1377 }
1378 fn visit_def_id(
1379 &mut self,
1380 def_id: DefId,
1381 kind: &str,
1382 descr: &dyn fmt::Display,
1383 ) -> Self::Result {
1384 if self.check_def_id(def_id, kind, descr) {
1385 ControlFlow::Break(())
1386 } else {
1387 ControlFlow::Continue(())
1388 }
1389 }
1390}
1391
1392struct PrivateItemsInPublicInterfacesChecker<'a, 'tcx> {
1393 tcx: TyCtxt<'tcx>,
1394 effective_visibilities: &'a EffectiveVisibilities,
1395}
1396
1397impl<'tcx> PrivateItemsInPublicInterfacesChecker<'_, 'tcx> {
1398 fn check(
1399 &self,
1400 def_id: LocalDefId,
1401 required_visibility: ty::Visibility,
1402 required_effective_vis: Option<EffectiveVisibility>,
1403 ) -> SearchInterfaceForPrivateItemsVisitor<'tcx> {
1404 SearchInterfaceForPrivateItemsVisitor {
1405 tcx: self.tcx,
1406 item_def_id: def_id,
1407 required_visibility,
1408 required_effective_vis,
1409 ..
1410 }
1411 }
1412
1413 fn check_unnameable(&self, def_id: LocalDefId, effective_vis: Option<EffectiveVisibility>) {
1414 let Some(effective_vis) = effective_vis else {
1415 return;
1416 };
1417
1418 let reexported_at_vis = effective_vis.at_level(Level::Reexported);
1419 let reachable_at_vis = effective_vis.at_level(Level::Reachable);
1420
1421 if reachable_at_vis.is_public() && reexported_at_vis != reachable_at_vis {
1422 let hir_id = self.tcx.local_def_id_to_hir_id(def_id);
1423 let span = self.tcx.def_span(def_id.to_def_id());
1424 self.tcx.emit_node_span_lint(
1425 lint::builtin::UNNAMEABLE_TYPES,
1426 hir_id,
1427 span,
1428 UnnameableTypesLint {
1429 span,
1430 kind: self.tcx.def_descr(def_id.to_def_id()),
1431 descr: (&LazyDefPathStr { def_id: def_id.to_def_id(), tcx: self.tcx }).into(),
1432 reachable_vis: &reachable_at_vis.to_string(def_id, self.tcx),
1433 reexported_vis: &reexported_at_vis.to_string(def_id, self.tcx),
1434 },
1435 );
1436 }
1437 }
1438
1439 fn check_assoc_item(
1440 &self,
1441 item: &ty::AssocItem,
1442 vis: ty::Visibility,
1443 effective_vis: Option<EffectiveVisibility>,
1444 ) {
1445 let mut check = self.check(item.def_id.expect_local(), vis, effective_vis);
1446
1447 let is_assoc_ty = item.is_type();
1448 check.hard_error = is_assoc_ty;
1449 check.generics().predicates();
1450 if assoc_has_type_of(self.tcx, item) {
1451 check.ty();
1452 }
1453 if is_assoc_ty && item.container == AssocContainer::Trait {
1454 check.hard_error = false;
1457 check.bounds();
1458 }
1459 }
1460
1461 fn get(&self, def_id: LocalDefId) -> Option<EffectiveVisibility> {
1462 self.effective_visibilities.effective_vis(def_id).copied()
1463 }
1464
1465 fn check_item(&self, id: ItemId) {
1466 let tcx = self.tcx;
1467 let def_id = id.owner_id.def_id;
1468 let item_visibility = tcx.local_visibility(def_id);
1469 let effective_vis = self.get(def_id);
1470 let def_kind = tcx.def_kind(def_id);
1471
1472 match def_kind {
1473 DefKind::Const { .. } | DefKind::Static { .. } | DefKind::Fn | DefKind::TyAlias => {
1474 if let DefKind::TyAlias = def_kind {
1475 self.check_unnameable(def_id, effective_vis);
1476 }
1477 self.check(def_id, item_visibility, effective_vis).generics().predicates().ty();
1478 }
1479 DefKind::OpaqueTy => {
1480 self.check(def_id, item_visibility, effective_vis).generics().bounds();
1483 }
1484 DefKind::Trait => {
1485 self.check_unnameable(def_id, effective_vis);
1486
1487 self.check(def_id, item_visibility, effective_vis).generics().predicates();
1488
1489 for assoc_item in tcx.associated_items(id.owner_id).in_definition_order() {
1490 self.check_assoc_item(assoc_item, item_visibility, effective_vis);
1491 }
1492 }
1493 DefKind::TraitAlias => {
1494 self.check(def_id, item_visibility, effective_vis).generics().predicates();
1495 }
1496 DefKind::Enum => {
1497 self.check_unnameable(def_id, effective_vis);
1498 self.check(def_id, item_visibility, effective_vis).generics().predicates();
1499
1500 let adt = tcx.adt_def(id.owner_id);
1501 for field in adt.all_fields() {
1502 self.check(field.did.expect_local(), item_visibility, effective_vis).ty();
1503 }
1504 }
1505 DefKind::Struct | DefKind::Union => {
1507 self.check_unnameable(def_id, effective_vis);
1508 self.check(def_id, item_visibility, effective_vis).generics().predicates();
1509
1510 let adt = tcx.adt_def(id.owner_id);
1511 for field in adt.all_fields() {
1512 let visibility = min(item_visibility, field.vis.expect_local(), tcx);
1513 let field_ev = self.get(field.did.expect_local());
1514
1515 self.check(field.did.expect_local(), visibility, field_ev).ty();
1516 }
1517 }
1518 DefKind::ForeignMod => {}
1520 DefKind::Impl { of_trait } => {
1525 let impl_vis =
1526 ty::Visibility::of_impl::<false>(def_id, of_trait, tcx, &Default::default());
1527
1528 let impl_ev = EffectiveVisibility::of_impl::<false>(
1540 def_id,
1541 of_trait,
1542 tcx,
1543 self.effective_visibilities,
1544 );
1545
1546 let mut check = self.check(def_id, impl_vis, Some(impl_ev));
1547
1548 if !of_trait {
1551 check.generics().predicates();
1552 }
1553
1554 check.skip_assoc_tys = true;
1558 check.ty();
1559 if of_trait {
1560 check.trait_ref();
1561 }
1562
1563 for assoc_item in tcx.associated_items(id.owner_id).in_definition_order() {
1564 let impl_item_vis = if !of_trait {
1565 min(tcx.local_visibility(assoc_item.def_id.expect_local()), impl_vis, tcx)
1566 } else {
1567 impl_vis
1568 };
1569
1570 let impl_item_ev = if !of_trait {
1571 self.get(assoc_item.def_id.expect_local())
1572 .map(|ev| ev.min(impl_ev, self.tcx))
1573 } else {
1574 Some(impl_ev)
1575 };
1576
1577 self.check_assoc_item(assoc_item, impl_item_vis, impl_item_ev);
1578 }
1579 }
1580 _ => {}
1581 }
1582 }
1583
1584 fn check_foreign_item(&self, id: ForeignItemId) {
1585 let tcx = self.tcx;
1586 let def_id = id.owner_id.def_id;
1587 let item_visibility = tcx.local_visibility(def_id);
1588 let effective_vis = self.get(def_id);
1589
1590 if let DefKind::ForeignTy = self.tcx.def_kind(def_id) {
1591 self.check_unnameable(def_id, effective_vis);
1592 }
1593
1594 self.check(def_id, item_visibility, effective_vis).generics().predicates().ty();
1595 }
1596}
1597
1598pub fn provide(providers: &mut Providers) {
1599 *providers = Providers {
1600 effective_visibilities,
1601 check_private_in_public,
1602 check_mod_privacy,
1603 ..*providers
1604 };
1605}
1606
1607fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
1608 let mut visitor = NamePrivacyVisitor { tcx, maybe_typeck_results: None };
1610 tcx.hir_visit_item_likes_in_module(module_def_id, &mut visitor);
1611
1612 let span = tcx.def_span(module_def_id);
1615 let mut visitor = TypePrivacyVisitor { tcx, module_def_id, maybe_typeck_results: None, span };
1616
1617 let module = tcx.hir_module_items(module_def_id);
1618 for def_id in module.definitions() {
1619 let _ = rustc_ty_utils::sig_types::walk_types(tcx, def_id, &mut visitor);
1620
1621 if let Some(body_id) = tcx.hir_maybe_body_owned_by(def_id) {
1622 visitor.visit_nested_body(body_id.id());
1623 }
1624
1625 if let DefKind::Impl { of_trait: true } = tcx.def_kind(def_id) {
1626 let trait_ref = tcx.impl_trait_ref(def_id);
1627 let trait_ref = trait_ref.instantiate_identity().skip_norm_wip();
1628 visitor.span =
1629 tcx.hir_expect_item(def_id).expect_impl().of_trait.unwrap().trait_ref.path.span;
1630 let _ =
1631 visitor.visit_def_id(trait_ref.def_id, "trait", &trait_ref.print_only_trait_path());
1632 }
1633 }
1634}
1635
1636fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities {
1637 let mut visitor = EmbargoVisitor {
1640 tcx,
1641 effective_visibilities: tcx.resolutions(()).effective_visibilities.clone(),
1642 changed: false,
1643 };
1644
1645 visitor.effective_visibilities.check_invariants(tcx);
1646
1647 let impl_trait_pass = !tcx.sess.opts.actually_rustdoc;
1651 if impl_trait_pass {
1652 let krate = tcx.hir_crate_items(());
1655 for id in krate.opaques() {
1656 let opaque = tcx.hir_node_by_def_id(id).expect_opaque_ty();
1657 let should_visit = match opaque.origin {
1658 hir::OpaqueTyOrigin::FnReturn {
1659 parent,
1660 in_trait_or_impl: Some(hir::RpitContext::Trait),
1661 }
1662 | hir::OpaqueTyOrigin::AsyncFn {
1663 parent,
1664 in_trait_or_impl: Some(hir::RpitContext::Trait),
1665 } => match tcx.hir_node_by_def_id(parent).expect_trait_item().expect_fn().1 {
1666 hir::TraitFn::Required(_) => false,
1667 hir::TraitFn::Provided(..) => true,
1668 },
1669
1670 hir::OpaqueTyOrigin::FnReturn {
1673 in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
1674 ..
1675 }
1676 | hir::OpaqueTyOrigin::AsyncFn {
1677 in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
1678 ..
1679 }
1680 | hir::OpaqueTyOrigin::TyAlias { .. } => true,
1681 };
1682 if should_visit {
1683 let pub_ev = EffectiveVisibility::from_vis(ty::Visibility::Public);
1687 visitor
1688 .reach_through_impl_trait(opaque.def_id, pub_ev)
1689 .generics()
1690 .predicates()
1691 .ty();
1692 }
1693 }
1694
1695 visitor.changed = false;
1696 }
1697
1698 for (&adt_def_id, macro_mods) in &tcx.resolutions(()).macro_reachable_adts {
1701 let struct_def = tcx.adt_def(adt_def_id);
1702 let Some(struct_ev) = visitor.effective_visibilities.effective_vis(adt_def_id).copied()
1703 else {
1704 continue;
1705 };
1706 for field in &struct_def.non_enum_variant().fields {
1707 let def_id = field.did.expect_local();
1708 let field_vis = tcx.local_visibility(def_id);
1709
1710 for ¯o_mod in macro_mods {
1711 if field_vis.is_accessible_from(macro_mod, tcx) {
1712 visitor.reach(def_id, struct_ev).ty();
1713 }
1714 }
1715 }
1716 }
1717
1718 let crate_items = tcx.hir_crate_items(());
1719 loop {
1720 for id in crate_items.free_items() {
1721 visitor.check_def_id(id.owner_id);
1722 }
1723 for id in crate_items.foreign_items() {
1724 visitor.check_def_id(id.owner_id);
1725 }
1726 if visitor.changed {
1727 visitor.changed = false;
1728 } else {
1729 break;
1730 }
1731 }
1732 visitor.effective_visibilities.check_invariants(tcx);
1733
1734 let check_visitor =
1735 TestReachabilityVisitor { tcx, effective_visibilities: &visitor.effective_visibilities };
1736 for id in crate_items.owners() {
1737 check_visitor.check_def_id(id);
1738 }
1739
1740 tcx.arena.alloc(visitor.effective_visibilities)
1741}
1742
1743fn check_private_in_public(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
1744 let effective_visibilities = tcx.effective_visibilities(());
1745 let checker = PrivateItemsInPublicInterfacesChecker { tcx, effective_visibilities };
1747
1748 let crate_items = tcx.hir_module_items(module_def_id);
1749 let _ = crate_items.par_items(|id| Ok(checker.check_item(id)));
1750 let _ = crate_items.par_foreign_items(|id| Ok(checker.check_foreign_item(id)));
1751}