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