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