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(
213 data @ ty::AliasTy {
214 kind:
215 kind @ (ty::Inherent { def_id }
216 | ty::Free { def_id }
217 | ty::Projection { def_id }),
218 ..
219 },
220 ) => {
221 if self.def_id_visitor.skip_assoc_tys() {
222 return V::Result::output();
228 }
229 if !self.visited_tys.insert(ty) {
230 return V::Result::output();
234 }
235
236 match ::rustc_ast_ir::visit::VisitorResult::branch(self.def_id_visitor.visit_def_id(def_id,
match kind {
ty::Inherent { .. } | ty::Projection { .. } =>
"associated type",
ty::Free { .. } => "type alias",
ty::Opaque { .. } =>
::core::panicking::panic("internal error: entered unreachable code"),
}, &LazyDefPathStr { def_id, tcx })) {
core::ops::ControlFlow::Continue(()) =>
(),
#[allow(unreachable_code)]
core::ops::ControlFlow::Break(r) => {
return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
}
};try_visit!(self.def_id_visitor.visit_def_id(
237 def_id,
238 match kind {
239 ty::Inherent { .. } | ty::Projection { .. } => "associated type",
240 ty::Free { .. } => "type alias",
241 ty::Opaque { .. } => unreachable!(),
242 },
243 &LazyDefPathStr { def_id, tcx },
244 ));
245
246 return if V::SHALLOW {
248 V::Result::output()
249 } else if #[allow(non_exhaustive_omitted_patterns)] match kind {
ty::Projection { .. } => true,
_ => false,
}matches!(kind, ty::Projection { .. }) {
250 self.visit_projection_term(data.into())
251 } else {
252 V::Result::from_branch(
253 data.args.iter().try_for_each(|arg| arg.visit_with(self).branch()),
254 )
255 };
256 }
257 ty::Dynamic(predicates, ..) => {
258 for predicate in predicates {
261 let trait_ref = match predicate.skip_binder() {
262 ty::ExistentialPredicate::Trait(trait_ref) => trait_ref,
263 ty::ExistentialPredicate::Projection(proj) => proj.trait_ref(tcx),
264 ty::ExistentialPredicate::AutoTrait(def_id) => {
265 ty::ExistentialTraitRef::new(tcx, def_id, ty::GenericArgs::empty())
266 }
267 };
268 let ty::ExistentialTraitRef { def_id, .. } = trait_ref;
269 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));
270 }
271 }
272 ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, .. }) => {
273 if self.visited_tys.insert(ty) {
275 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()));
283 }
284 }
285 ty::Bool
288 | ty::Char
289 | ty::Int(..)
290 | ty::Uint(..)
291 | ty::Float(..)
292 | ty::Str
293 | ty::Never
294 | ty::Array(..)
295 | ty::Slice(..)
296 | ty::Tuple(..)
297 | ty::RawPtr(..)
298 | ty::Ref(..)
299 | ty::Pat(..)
300 | ty::FnPtr(..)
301 | ty::UnsafeBinder(_)
302 | ty::Param(..)
303 | ty::Bound(..)
304 | ty::Error(_)
305 | ty::CoroutineWitness(..) => {}
306 ty::Placeholder(..) | ty::Infer(..) => {
307 ::rustc_middle::util::bug::bug_fmt(format_args!("unexpected type: {0:?}", ty))bug!("unexpected type: {:?}", ty)
308 }
309 }
310
311 if V::SHALLOW { V::Result::output() } else { ty.super_visit_with(self) }
312 }
313
314 fn visit_const(&mut self, c: Const<'tcx>) -> Self::Result {
315 let tcx = self.def_id_visitor.tcx();
316 tcx.expand_abstract_consts(c).super_visit_with(self)
317 }
318}
319
320fn assoc_has_type_of(tcx: TyCtxt<'_>, item: &ty::AssocItem) -> bool {
321 if let ty::AssocKind::Type { data: ty::AssocTypeData::Normal(..) } = item.kind
322 && let hir::Node::TraitItem(item) =
323 tcx.hir_node(tcx.local_def_id_to_hir_id(item.def_id.expect_local()))
324 && let hir::TraitItemKind::Type(_, None) = item.kind
325 {
326 false
327 } else {
328 true
329 }
330}
331
332fn min(vis1: ty::Visibility, vis2: ty::Visibility, tcx: TyCtxt<'_>) -> ty::Visibility {
333 if vis1.is_at_least(vis2, tcx) { vis2 } else { vis1 }
334}
335
336struct FindMin<'a, 'tcx, VL: VisibilityLike, const SHALLOW: bool> {
338 tcx: TyCtxt<'tcx>,
339 effective_visibilities: &'a EffectiveVisibilities,
340 min: VL,
341}
342
343impl<'a, 'tcx, VL: VisibilityLike, const SHALLOW: bool> DefIdVisitor<'tcx>
344 for FindMin<'a, 'tcx, VL, SHALLOW>
345{
346 const SHALLOW: bool = SHALLOW;
347 fn skip_assoc_tys(&self) -> bool {
348 true
349 }
350 fn tcx(&self) -> TyCtxt<'tcx> {
351 self.tcx
352 }
353 fn visit_def_id(&mut self, def_id: DefId, _kind: &str, _descr: &dyn fmt::Display) {
354 if let Some(def_id) = def_id.as_local() {
355 self.min = VL::new_min(self, def_id);
356 }
357 }
358}
359
360trait VisibilityLike: Sized {
361 const MAX: Self;
362 fn new_min<const SHALLOW: bool>(
363 find: &FindMin<'_, '_, Self, SHALLOW>,
364 def_id: LocalDefId,
365 ) -> Self;
366
367 fn of_impl<const SHALLOW: bool>(
370 def_id: LocalDefId,
371 of_trait: bool,
372 tcx: TyCtxt<'_>,
373 effective_visibilities: &EffectiveVisibilities,
374 ) -> Self {
375 let mut find = FindMin::<_, SHALLOW> { tcx, effective_visibilities, min: Self::MAX };
376 find.visit(tcx.type_of(def_id).instantiate_identity());
377 if of_trait {
378 find.visit_trait(tcx.impl_trait_ref(def_id).instantiate_identity());
379 }
380 find.min
381 }
382}
383
384impl VisibilityLike for ty::Visibility {
385 const MAX: Self = ty::Visibility::Public;
386 fn new_min<const SHALLOW: bool>(
387 find: &FindMin<'_, '_, Self, SHALLOW>,
388 def_id: LocalDefId,
389 ) -> Self {
390 min(find.tcx.local_visibility(def_id), find.min, find.tcx)
391 }
392}
393
394impl VisibilityLike for EffectiveVisibility {
395 const MAX: Self = EffectiveVisibility::from_vis(ty::Visibility::Public);
396 fn new_min<const SHALLOW: bool>(
397 find: &FindMin<'_, '_, Self, SHALLOW>,
398 def_id: LocalDefId,
399 ) -> Self {
400 let effective_vis =
401 find.effective_visibilities.effective_vis(def_id).copied().unwrap_or_else(|| {
402 let private_vis = ty::Visibility::Restricted(
403 find.tcx.parent_module_from_def_id(def_id).to_local_def_id(),
404 );
405 EffectiveVisibility::from_vis(private_vis)
406 });
407
408 effective_vis.min(find.min, find.tcx)
409 }
410}
411
412struct EmbargoVisitor<'tcx> {
414 tcx: TyCtxt<'tcx>,
415
416 effective_visibilities: EffectiveVisibilities,
418 macro_reachable: FxHashSet<(LocalModDefId, LocalModDefId)>,
431 changed: bool,
433}
434
435struct ReachEverythingInTheInterfaceVisitor<'a, 'tcx> {
436 effective_vis: EffectiveVisibility,
437 item_def_id: LocalDefId,
438 ev: &'a mut EmbargoVisitor<'tcx>,
439 level: Level,
440}
441
442impl<'tcx> EmbargoVisitor<'tcx> {
443 fn get(&self, def_id: LocalDefId) -> Option<EffectiveVisibility> {
444 self.effective_visibilities.effective_vis(def_id).copied()
445 }
446
447 fn update(
449 &mut self,
450 def_id: LocalDefId,
451 inherited_effective_vis: EffectiveVisibility,
452 level: Level,
453 ) {
454 let nominal_vis = self.tcx.local_visibility(def_id);
455 self.update_eff_vis(def_id, inherited_effective_vis, Some(nominal_vis), level);
456 }
457
458 fn update_eff_vis(
459 &mut self,
460 def_id: LocalDefId,
461 inherited_effective_vis: EffectiveVisibility,
462 max_vis: Option<ty::Visibility>,
463 level: Level,
464 ) {
465 let private_vis =
467 ty::Visibility::Restricted(self.tcx.parent_module_from_def_id(def_id).into());
468 if max_vis != Some(private_vis) {
469 self.changed |= self.effective_visibilities.update(
470 def_id,
471 max_vis,
472 || private_vis,
473 inherited_effective_vis,
474 level,
475 self.tcx,
476 );
477 }
478 }
479
480 fn reach(
481 &mut self,
482 def_id: LocalDefId,
483 effective_vis: EffectiveVisibility,
484 ) -> ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
485 ReachEverythingInTheInterfaceVisitor {
486 effective_vis,
487 item_def_id: def_id,
488 ev: self,
489 level: Level::Reachable,
490 }
491 }
492
493 fn reach_through_impl_trait(
494 &mut self,
495 def_id: LocalDefId,
496 effective_vis: EffectiveVisibility,
497 ) -> ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
498 ReachEverythingInTheInterfaceVisitor {
499 effective_vis,
500 item_def_id: def_id,
501 ev: self,
502 level: Level::ReachableThroughImplTrait,
503 }
504 }
505
506 fn update_reachability_from_macro(
509 &mut self,
510 local_def_id: LocalDefId,
511 md: &MacroDef,
512 macro_ev: EffectiveVisibility,
513 ) {
514 let hir_id = self.tcx.local_def_id_to_hir_id(local_def_id);
516 let attrs = self.tcx.hir_attrs(hir_id);
517
518 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)
519 .unwrap_or(Transparency::fallback(md.macro_rules))
520 != Transparency::Opaque
521 {
522 return;
523 }
524
525 let macro_module_def_id = self.tcx.local_parent(local_def_id);
526 if self.tcx.def_kind(macro_module_def_id) != DefKind::Mod {
527 return;
529 }
530 let macro_module_def_id = LocalModDefId::new_unchecked(macro_module_def_id);
532
533 if self.effective_visibilities.public_at_level(local_def_id).is_none() {
534 return;
535 }
536
537 let mut module_def_id = macro_module_def_id;
540 loop {
541 let changed_reachability =
542 self.update_macro_reachable(module_def_id, macro_module_def_id, macro_ev);
543 if changed_reachability || module_def_id == LocalModDefId::CRATE_DEF_ID {
544 break;
545 }
546 module_def_id = LocalModDefId::new_unchecked(self.tcx.local_parent(module_def_id));
547 }
548 }
549
550 fn update_macro_reachable(
553 &mut self,
554 module_def_id: LocalModDefId,
555 defining_mod: LocalModDefId,
556 macro_ev: EffectiveVisibility,
557 ) -> bool {
558 if self.macro_reachable.insert((module_def_id, defining_mod)) {
559 for child in self.tcx.module_children_local(module_def_id.to_local_def_id()) {
560 if let Res::Def(def_kind, def_id) = child.res
561 && let Some(def_id) = def_id.as_local()
562 && child.vis.is_accessible_from(defining_mod, self.tcx)
563 {
564 let vis = self.tcx.local_visibility(def_id);
565 self.update_macro_reachable_def(def_id, def_kind, vis, defining_mod, macro_ev);
566 }
567 }
568 true
569 } else {
570 false
571 }
572 }
573
574 fn update_macro_reachable_def(
575 &mut self,
576 def_id: LocalDefId,
577 def_kind: DefKind,
578 vis: ty::Visibility,
579 module: LocalModDefId,
580 macro_ev: EffectiveVisibility,
581 ) {
582 self.update(def_id, macro_ev, Level::Reachable);
583 match def_kind {
584 DefKind::Const { .. }
586 | DefKind::Static { .. }
587 | DefKind::TraitAlias
588 | DefKind::TyAlias => {
589 if vis.is_accessible_from(module, self.tcx) {
590 self.update(def_id, macro_ev, Level::Reachable);
591 }
592 }
593
594 DefKind::Macro(_) => {
599 let item = self.tcx.hir_expect_item(def_id);
600 if let hir::ItemKind::Macro(_, MacroDef { macro_rules: false, .. }, _) = item.kind {
601 if vis.is_accessible_from(module, self.tcx) {
602 self.update(def_id, macro_ev, Level::Reachable);
603 }
604 }
605 }
606
607 DefKind::Mod => {
612 if vis.is_accessible_from(module, self.tcx) {
613 self.update_macro_reachable(
614 LocalModDefId::new_unchecked(def_id),
615 module,
616 macro_ev,
617 );
618 }
619 }
620
621 DefKind::Struct | DefKind::Union => {
622 let struct_def = self.tcx.adt_def(def_id);
624 for field in &struct_def.non_enum_variant().fields {
625 let def_id = field.did.expect_local();
626 let field_vis = self.tcx.local_visibility(def_id);
627 if field_vis.is_accessible_from(module, self.tcx) {
628 self.reach(def_id, macro_ev).ty();
629 }
630 }
631 }
632
633 DefKind::AssocConst { .. }
636 | DefKind::AssocTy
637 | DefKind::ConstParam
638 | DefKind::Ctor(_, _)
639 | DefKind::Enum
640 | DefKind::ForeignTy
641 | DefKind::Fn
642 | DefKind::OpaqueTy
643 | DefKind::AssocFn
644 | DefKind::Trait
645 | DefKind::TyParam
646 | DefKind::Variant
647 | DefKind::LifetimeParam
648 | DefKind::ExternCrate
649 | DefKind::Use
650 | DefKind::ForeignMod
651 | DefKind::AnonConst
652 | DefKind::InlineConst
653 | DefKind::Field
654 | DefKind::GlobalAsm
655 | DefKind::Impl { .. }
656 | DefKind::Closure
657 | DefKind::SyntheticCoroutineBody => (),
658 }
659 }
660}
661
662impl<'tcx> EmbargoVisitor<'tcx> {
663 fn check_assoc_item(&mut self, item: &ty::AssocItem, item_ev: EffectiveVisibility) {
664 let def_id = item.def_id.expect_local();
665 let tcx = self.tcx;
666 let mut reach = self.reach(def_id, item_ev);
667 reach.generics().predicates();
668 if assoc_has_type_of(tcx, item) {
669 reach.ty();
670 }
671 if item.is_type() && item.container == AssocContainer::Trait {
672 reach.bounds();
673 }
674 }
675
676 fn check_def_id(&mut self, owner_id: OwnerId) {
677 let item_ev = self.get(owner_id.def_id);
680 match self.tcx.def_kind(owner_id) {
681 DefKind::Use | DefKind::ExternCrate | DefKind::GlobalAsm => {}
683 DefKind::Mod => {}
685 DefKind::Macro { .. } => {
686 if let Some(item_ev) = item_ev {
687 let (_, macro_def, _) =
688 self.tcx.hir_expect_item(owner_id.def_id).expect_macro();
689 self.update_reachability_from_macro(owner_id.def_id, macro_def, item_ev);
690 }
691 }
692 DefKind::ForeignTy
693 | DefKind::Const { .. }
694 | DefKind::Static { .. }
695 | DefKind::Fn
696 | DefKind::TyAlias => {
697 if let Some(item_ev) = item_ev {
698 self.reach(owner_id.def_id, item_ev).generics().predicates().ty();
699 }
700 }
701 DefKind::Trait => {
702 if let Some(item_ev) = item_ev {
703 self.reach(owner_id.def_id, item_ev).generics().predicates();
704
705 for assoc_item in self.tcx.associated_items(owner_id).in_definition_order() {
706 let def_id = assoc_item.def_id.expect_local();
707 self.update(def_id, item_ev, Level::Reachable);
708
709 self.check_assoc_item(assoc_item, item_ev);
710 }
711 }
712 }
713 DefKind::TraitAlias => {
714 if let Some(item_ev) = item_ev {
715 self.reach(owner_id.def_id, item_ev).generics().predicates();
716 }
717 }
718 DefKind::Impl { of_trait } => {
719 let item_ev = EffectiveVisibility::of_impl::<true>(
730 owner_id.def_id,
731 of_trait,
732 self.tcx,
733 &self.effective_visibilities,
734 );
735
736 self.update_eff_vis(owner_id.def_id, item_ev, None, Level::Direct);
737
738 {
739 let mut reach = self.reach(owner_id.def_id, item_ev);
740 reach.generics().predicates().ty();
741 if of_trait {
742 reach.trait_ref();
743 }
744 }
745
746 for assoc_item in self.tcx.associated_items(owner_id).in_definition_order() {
747 let def_id = assoc_item.def_id.expect_local();
748 let max_vis =
749 if of_trait { None } else { Some(self.tcx.local_visibility(def_id)) };
750 self.update_eff_vis(def_id, item_ev, max_vis, Level::Direct);
751
752 if let Some(impl_item_ev) = self.get(def_id) {
753 self.check_assoc_item(assoc_item, impl_item_ev);
754 }
755 }
756 }
757 DefKind::Enum => {
758 if let Some(item_ev) = item_ev {
759 self.reach(owner_id.def_id, item_ev).generics().predicates();
760 }
761 let def = self.tcx.adt_def(owner_id);
762 for variant in def.variants() {
763 if let Some(item_ev) = item_ev {
764 self.update(variant.def_id.expect_local(), item_ev, Level::Reachable);
765 }
766
767 if let Some(variant_ev) = self.get(variant.def_id.expect_local()) {
768 if let Some(ctor_def_id) = variant.ctor_def_id() {
769 self.update(ctor_def_id.expect_local(), variant_ev, Level::Reachable);
770 }
771
772 for field in &variant.fields {
773 let field = field.did.expect_local();
774 self.update(field, variant_ev, Level::Reachable);
775 self.reach(field, variant_ev).ty();
776 }
777 self.reach(owner_id.def_id, variant_ev).ty();
780 }
781 if let Some(ctor_def_id) = variant.ctor_def_id() {
782 if let Some(ctor_ev) = self.get(ctor_def_id.expect_local()) {
783 self.reach(owner_id.def_id, ctor_ev).ty();
784 }
785 }
786 }
787 }
788 DefKind::Struct | DefKind::Union => {
789 let def = self.tcx.adt_def(owner_id).non_enum_variant();
790 if let Some(item_ev) = item_ev {
791 self.reach(owner_id.def_id, item_ev).generics().predicates();
792 for field in &def.fields {
793 let field = field.did.expect_local();
794 self.update(field, item_ev, Level::Reachable);
795 if let Some(field_ev) = self.get(field) {
796 self.reach(field, field_ev).ty();
797 }
798 }
799 }
800 if let Some(ctor_def_id) = def.ctor_def_id() {
801 if let Some(item_ev) = item_ev {
802 self.update(ctor_def_id.expect_local(), item_ev, Level::Reachable);
803 }
804 if let Some(ctor_ev) = self.get(ctor_def_id.expect_local()) {
805 self.reach(owner_id.def_id, ctor_ev).ty();
806 }
807 }
808 }
809 DefKind::ForeignMod => {}
811 DefKind::Field
812 | DefKind::Variant
813 | DefKind::AssocFn
814 | DefKind::AssocTy
815 | DefKind::AssocConst { .. }
816 | DefKind::TyParam
817 | DefKind::AnonConst
818 | DefKind::InlineConst
819 | DefKind::OpaqueTy
820 | DefKind::Closure
821 | DefKind::SyntheticCoroutineBody
822 | DefKind::ConstParam
823 | DefKind::LifetimeParam
824 | DefKind::Ctor(..) => {
825 ::rustc_middle::util::bug::bug_fmt(format_args!("should be checked while checking parent"))bug!("should be checked while checking parent")
826 }
827 }
828 }
829}
830
831impl ReachEverythingInTheInterfaceVisitor<'_, '_> {
832 fn generics(&mut self) -> &mut Self {
833 for param in &self.ev.tcx.generics_of(self.item_def_id).own_params {
834 if let GenericParamDefKind::Const { .. } = param.kind {
835 self.visit(self.ev.tcx.type_of(param.def_id).instantiate_identity());
836 }
837 if let Some(default) = param.default_value(self.ev.tcx) {
838 self.visit(default.instantiate_identity());
839 }
840 }
841 self
842 }
843
844 fn predicates(&mut self) -> &mut Self {
845 self.visit_predicates(self.ev.tcx.explicit_predicates_of(self.item_def_id));
846 self
847 }
848
849 fn bounds(&mut self) -> &mut Self {
850 self.visit_clauses(self.ev.tcx.explicit_item_bounds(self.item_def_id).skip_binder());
851 self
852 }
853
854 fn ty(&mut self) -> &mut Self {
855 self.visit(self.ev.tcx.type_of(self.item_def_id).instantiate_identity());
856 self
857 }
858
859 fn trait_ref(&mut self) -> &mut Self {
860 self.visit_trait(self.ev.tcx.impl_trait_ref(self.item_def_id).instantiate_identity());
861 self
862 }
863}
864
865impl<'tcx> DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
866 fn tcx(&self) -> TyCtxt<'tcx> {
867 self.ev.tcx
868 }
869 fn visit_def_id(&mut self, def_id: DefId, _kind: &str, _descr: &dyn fmt::Display) {
870 if let Some(def_id) = def_id.as_local() {
871 let max_vis = (self.level != Level::ReachableThroughImplTrait)
875 .then(|| self.ev.tcx.local_visibility(def_id));
876 self.ev.update_eff_vis(def_id, self.effective_vis, max_vis, self.level);
877 }
878 }
879}
880
881pub struct TestReachabilityVisitor<'a, 'tcx> {
883 tcx: TyCtxt<'tcx>,
884 effective_visibilities: &'a EffectiveVisibilities,
885}
886
887impl<'a, 'tcx> TestReachabilityVisitor<'a, 'tcx> {
888 fn effective_visibility_diagnostic(&self, def_id: LocalDefId) {
889 if {
{
'done:
{
for i in
::rustc_hir::attrs::HasAttrs::get_attrs(def_id, &self.tcx) {
#[allow(unused_imports)]
use rustc_hir::attrs::AttributeKind::*;
let i: &rustc_hir::Attribute = i;
match i {
rustc_hir::Attribute::Parsed(RustcEffectiveVisibility) => {
break 'done Some(());
}
rustc_hir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}.is_some()find_attr!(self.tcx, def_id, RustcEffectiveVisibility) {
890 let mut error_msg = String::new();
891 let span = self.tcx.def_span(def_id.to_def_id());
892 if let Some(effective_vis) = self.effective_visibilities.effective_vis(def_id) {
893 for level in Level::all_levels() {
894 let vis_str = effective_vis.at_level(level).to_string(def_id, self.tcx);
895 if level != Level::Direct {
896 error_msg.push_str(", ");
897 }
898 error_msg.push_str(&::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?}: {1}", level, vis_str))
})format!("{level:?}: {vis_str}"));
899 }
900 } else {
901 error_msg.push_str("not in the table");
902 }
903 self.tcx.dcx().emit_err(ReportEffectiveVisibility { span, descr: error_msg });
904 }
905 }
906}
907
908impl<'a, 'tcx> TestReachabilityVisitor<'a, 'tcx> {
909 fn check_def_id(&self, owner_id: OwnerId) {
910 self.effective_visibility_diagnostic(owner_id.def_id);
911
912 match self.tcx.def_kind(owner_id) {
913 DefKind::Enum => {
914 let def = self.tcx.adt_def(owner_id.def_id);
915 for variant in def.variants() {
916 self.effective_visibility_diagnostic(variant.def_id.expect_local());
917 if let Some(ctor_def_id) = variant.ctor_def_id() {
918 self.effective_visibility_diagnostic(ctor_def_id.expect_local());
919 }
920 for field in &variant.fields {
921 self.effective_visibility_diagnostic(field.did.expect_local());
922 }
923 }
924 }
925 DefKind::Struct | DefKind::Union => {
926 let def = self.tcx.adt_def(owner_id.def_id).non_enum_variant();
927 if let Some(ctor_def_id) = def.ctor_def_id() {
928 self.effective_visibility_diagnostic(ctor_def_id.expect_local());
929 }
930 for field in &def.fields {
931 self.effective_visibility_diagnostic(field.did.expect_local());
932 }
933 }
934 _ => {}
935 }
936 }
937}
938
939struct NamePrivacyVisitor<'tcx> {
945 tcx: TyCtxt<'tcx>,
946 maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
947}
948
949impl<'tcx> NamePrivacyVisitor<'tcx> {
950 #[track_caller]
954 fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> {
955 self.maybe_typeck_results
956 .expect("`NamePrivacyVisitor::typeck_results` called outside of body")
957 }
958
959 fn check_field(
961 &self,
962 hir_id: hir::HirId, use_ctxt: Span, def: ty::AdtDef<'tcx>, field: &'tcx ty::FieldDef,
966 ) -> bool {
967 if def.is_enum() {
968 return true;
969 }
970
971 let ident = Ident::new(sym::dummy, use_ctxt);
973 let (_, def_id) = self.tcx.adjust_ident_and_get_scope(ident, def.did(), hir_id);
974 !field.vis.is_accessible_from(def_id, self.tcx)
975 }
976
977 fn emit_unreachable_field_error(
979 &self,
980 fields: Vec<(Symbol, Span, bool )>,
981 def: ty::AdtDef<'tcx>, update_syntax: Option<Span>,
983 struct_span: Span,
984 ) {
985 if def.is_enum() || fields.is_empty() {
986 return;
987 }
988
989 let Some(field_names) = listify(&fields[..], |(n, _, _)| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}`", n))
})format!("`{n}`")) else { return };
1001 let span: MultiSpan = fields.iter().map(|(_, span, _)| *span).collect::<Vec<Span>>().into();
1002
1003 let rest_field_names: Vec<_> =
1005 fields.iter().filter(|(_, _, is_present)| !is_present).map(|(n, _, _)| n).collect();
1006 let rest_len = rest_field_names.len();
1007 let rest_field_names =
1008 listify(&rest_field_names[..], |n| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}`", n))
})format!("`{n}`")).unwrap_or_default();
1009 let labels = fields
1011 .iter()
1012 .filter(|(_, _, is_present)| *is_present)
1013 .map(|(_, span, _)| FieldIsPrivateLabel::Other { span: *span })
1014 .chain(update_syntax.iter().map(|span| FieldIsPrivateLabel::IsUpdateSyntax {
1015 span: *span,
1016 rest_field_names: rest_field_names.clone(),
1017 rest_len,
1018 }))
1019 .collect();
1020
1021 self.tcx.dcx().emit_err(FieldIsPrivate {
1022 span,
1023 struct_span: if self
1024 .tcx
1025 .sess
1026 .source_map()
1027 .is_multiline(fields[0].1.between(struct_span))
1028 {
1029 Some(struct_span)
1030 } else {
1031 None
1032 },
1033 field_names,
1034 variant_descr: def.variant_descr(),
1035 def_path_str: self.tcx.def_path_str(def.did()),
1036 labels,
1037 len: fields.len(),
1038 });
1039 }
1040
1041 fn check_expanded_fields(
1042 &self,
1043 adt: ty::AdtDef<'tcx>,
1044 variant: &'tcx ty::VariantDef,
1045 fields: &[hir::ExprField<'tcx>],
1046 hir_id: hir::HirId,
1047 span: Span,
1048 struct_span: Span,
1049 ) {
1050 let mut failed_fields = ::alloc::vec::Vec::new()vec![];
1051 for (vf_index, variant_field) in variant.fields.iter_enumerated() {
1052 let field =
1053 fields.iter().find(|f| self.typeck_results().field_index(f.hir_id) == vf_index);
1054 let (hir_id, use_ctxt, span) = match field {
1055 Some(field) => (field.hir_id, field.ident.span, field.span),
1056 None => (hir_id, span, span),
1057 };
1058 if self.check_field(hir_id, use_ctxt, adt, variant_field) {
1059 let name = match field {
1060 Some(field) => field.ident.name,
1061 None => variant_field.name,
1062 };
1063 failed_fields.push((name, span, field.is_some()));
1064 }
1065 }
1066 self.emit_unreachable_field_error(failed_fields, adt, Some(span), struct_span);
1067 }
1068}
1069
1070impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> {
1071 fn visit_nested_body(&mut self, body_id: hir::BodyId) {
1072 let new_typeck_results = self.tcx.typeck_body(body_id);
1073 if new_typeck_results.tainted_by_errors.is_some() {
1075 return;
1076 }
1077 let old_maybe_typeck_results = self.maybe_typeck_results.replace(new_typeck_results);
1078 self.visit_body(self.tcx.hir_body(body_id));
1079 self.maybe_typeck_results = old_maybe_typeck_results;
1080 }
1081
1082 fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
1083 if let hir::ExprKind::Struct(qpath, fields, ref base) = expr.kind {
1084 let res = self.typeck_results().qpath_res(qpath, expr.hir_id);
1085 let adt = self.typeck_results().expr_ty(expr).ty_adt_def().unwrap();
1086 let variant = adt.variant_of_res(res);
1087 match *base {
1088 hir::StructTailExpr::Base(base) => {
1089 self.check_expanded_fields(
1093 adt,
1094 variant,
1095 fields,
1096 base.hir_id,
1097 base.span,
1098 qpath.span(),
1099 );
1100 }
1101 hir::StructTailExpr::DefaultFields(span) => {
1102 self.check_expanded_fields(
1103 adt,
1104 variant,
1105 fields,
1106 expr.hir_id,
1107 span,
1108 qpath.span(),
1109 );
1110 }
1111 hir::StructTailExpr::None | hir::StructTailExpr::NoneWithError(_) => {
1112 let mut failed_fields = ::alloc::vec::Vec::new()vec![];
1113 for field in fields {
1114 let (hir_id, use_ctxt) = (field.hir_id, field.ident.span);
1115 let index = self.typeck_results().field_index(field.hir_id);
1116 if self.check_field(hir_id, use_ctxt, adt, &variant.fields[index]) {
1117 failed_fields.push((field.ident.name, field.ident.span, true));
1118 }
1119 }
1120 self.emit_unreachable_field_error(failed_fields, adt, None, qpath.span());
1121 }
1122 }
1123 }
1124
1125 intravisit::walk_expr(self, expr);
1126 }
1127
1128 fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) {
1129 if let PatKind::Struct(ref qpath, fields, _) = pat.kind {
1130 let res = self.typeck_results().qpath_res(qpath, pat.hir_id);
1131 let adt = self.typeck_results().pat_ty(pat).ty_adt_def().unwrap();
1132 let variant = adt.variant_of_res(res);
1133 let mut failed_fields = ::alloc::vec::Vec::new()vec![];
1134 for field in fields {
1135 let (hir_id, use_ctxt) = (field.hir_id, field.ident.span);
1136 let index = self.typeck_results().field_index(field.hir_id);
1137 if self.check_field(hir_id, use_ctxt, adt, &variant.fields[index]) {
1138 failed_fields.push((field.ident.name, field.ident.span, true));
1139 }
1140 }
1141 self.emit_unreachable_field_error(failed_fields, adt, None, qpath.span());
1142 }
1143
1144 intravisit::walk_pat(self, pat);
1145 }
1146}
1147
1148struct TypePrivacyVisitor<'tcx> {
1153 tcx: TyCtxt<'tcx>,
1154 module_def_id: LocalModDefId,
1155 maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
1156 span: Span,
1157}
1158
1159impl<'tcx> TypePrivacyVisitor<'tcx> {
1160 fn item_is_accessible(&self, did: DefId) -> bool {
1161 self.tcx.visibility(did).is_accessible_from(self.module_def_id, self.tcx)
1162 }
1163
1164 fn check_expr_pat_type(&mut self, id: hir::HirId, span: Span) -> bool {
1166 self.span = span;
1167 let typeck_results = self
1168 .maybe_typeck_results
1169 .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"));
1170 try {
1171 self.visit(typeck_results.node_type(id))?;
1172 self.visit(typeck_results.node_args(id))?;
1173 if let Some(adjustments) = typeck_results.adjustments().get(id) {
1174 adjustments.iter().try_for_each(|adjustment| self.visit(adjustment.target))?;
1175 }
1176 }
1177 .is_break()
1178 }
1179
1180 fn check_def_id(&self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
1181 let is_error = !self.item_is_accessible(def_id);
1182 if is_error {
1183 self.tcx.dcx().emit_err(ItemIsPrivate { span: self.span, kind, descr: descr.into() });
1184 }
1185 is_error
1186 }
1187}
1188
1189impl<'tcx> rustc_ty_utils::sig_types::SpannedTypeVisitor<'tcx> for TypePrivacyVisitor<'tcx> {
1190 type Result = ControlFlow<()>;
1191 fn visit(&mut self, span: Span, value: impl TypeVisitable<TyCtxt<'tcx>>) -> Self::Result {
1192 self.span = span;
1193 value.visit_with(&mut self.skeleton())
1194 }
1195}
1196
1197impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
1198 fn visit_nested_body(&mut self, body_id: hir::BodyId) {
1199 let old_maybe_typeck_results =
1200 self.maybe_typeck_results.replace(self.tcx.typeck_body(body_id));
1201 self.visit_body(self.tcx.hir_body(body_id));
1202 self.maybe_typeck_results = old_maybe_typeck_results;
1203 }
1204
1205 fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
1206 self.span = hir_ty.span;
1207 if self
1208 .visit(
1209 self.maybe_typeck_results
1210 .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"))
1211 .node_type(hir_ty.hir_id),
1212 )
1213 .is_break()
1214 {
1215 return;
1216 }
1217
1218 intravisit::walk_ty(self, hir_ty);
1219 }
1220
1221 fn visit_infer(
1222 &mut self,
1223 inf_id: rustc_hir::HirId,
1224 inf_span: Span,
1225 _kind: InferKind<'tcx>,
1226 ) -> Self::Result {
1227 self.span = inf_span;
1228 if let Some(ty) = self
1229 .maybe_typeck_results
1230 .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"))
1231 .node_type_opt(inf_id)
1232 {
1233 if self.visit(ty).is_break() {
1234 return;
1235 }
1236 } else {
1237 }
1239
1240 self.visit_id(inf_id)
1241 }
1242
1243 fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
1245 if self.check_expr_pat_type(expr.hir_id, expr.span) {
1246 return;
1248 }
1249 match expr.kind {
1250 hir::ExprKind::Assign(_, rhs, _) | hir::ExprKind::Match(rhs, ..) => {
1251 if self.check_expr_pat_type(rhs.hir_id, rhs.span) {
1253 return;
1254 }
1255 }
1256 hir::ExprKind::MethodCall(segment, ..) => {
1257 self.span = segment.ident.span;
1259 let typeck_results = self
1260 .maybe_typeck_results
1261 .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"));
1262 if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) {
1263 if self.visit(self.tcx.type_of(def_id).instantiate_identity()).is_break() {
1264 return;
1265 }
1266 } else {
1267 self.tcx
1268 .dcx()
1269 .span_delayed_bug(expr.span, "no type-dependent def for method call");
1270 }
1271 }
1272 _ => {}
1273 }
1274
1275 intravisit::walk_expr(self, expr);
1276 }
1277
1278 fn visit_qpath(&mut self, qpath: &'tcx hir::QPath<'tcx>, id: hir::HirId, span: Span) {
1285 let def = match qpath {
1286 hir::QPath::Resolved(_, path) => match path.res {
1287 Res::Def(kind, def_id) => Some((kind, def_id)),
1288 _ => None,
1289 },
1290 hir::QPath::TypeRelative(..) => {
1291 match self.maybe_typeck_results {
1292 Some(typeck_results) => typeck_results.type_dependent_def(id),
1293 None => None,
1295 }
1296 }
1297 };
1298 let def = def.filter(|(kind, _)| {
1299 #[allow(non_exhaustive_omitted_patterns)] match kind {
DefKind::AssocFn | DefKind::AssocConst { .. } | DefKind::AssocTy |
DefKind::Static { .. } => true,
_ => false,
}matches!(
1300 kind,
1301 DefKind::AssocFn
1302 | DefKind::AssocConst { .. }
1303 | DefKind::AssocTy
1304 | DefKind::Static { .. }
1305 )
1306 });
1307 if let Some((kind, def_id)) = def {
1308 let is_local_static =
1309 if let DefKind::Static { .. } = kind { def_id.is_local() } else { false };
1310 if !self.item_is_accessible(def_id) && !is_local_static {
1311 let name = match *qpath {
1312 hir::QPath::Resolved(_, path) => Some(self.tcx.def_path_str(path.res.def_id())),
1313 hir::QPath::TypeRelative(_, segment) => Some(segment.ident.to_string()),
1314 };
1315 let kind = self.tcx.def_descr(def_id);
1316 let sess = self.tcx.sess;
1317 let _ = match name {
1318 Some(name) => {
1319 sess.dcx().emit_err(ItemIsPrivate { span, kind, descr: (&name).into() })
1320 }
1321 None => sess.dcx().emit_err(UnnamedItemIsPrivate { span, kind }),
1322 };
1323 return;
1324 }
1325 }
1326
1327 intravisit::walk_qpath(self, qpath, id);
1328 }
1329
1330 fn visit_pat(&mut self, pattern: &'tcx hir::Pat<'tcx>) {
1332 if self.check_expr_pat_type(pattern.hir_id, pattern.span) {
1333 return;
1335 }
1336
1337 intravisit::walk_pat(self, pattern);
1338 }
1339
1340 fn visit_local(&mut self, local: &'tcx hir::LetStmt<'tcx>) {
1341 if let Some(init) = local.init {
1342 if self.check_expr_pat_type(init.hir_id, init.span) {
1343 return;
1345 }
1346 }
1347
1348 intravisit::walk_local(self, local);
1349 }
1350}
1351
1352impl<'tcx> DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> {
1353 type Result = ControlFlow<()>;
1354 fn tcx(&self) -> TyCtxt<'tcx> {
1355 self.tcx
1356 }
1357 fn visit_def_id(
1358 &mut self,
1359 def_id: DefId,
1360 kind: &str,
1361 descr: &dyn fmt::Display,
1362 ) -> Self::Result {
1363 if self.check_def_id(def_id, kind, descr) {
1364 ControlFlow::Break(())
1365 } else {
1366 ControlFlow::Continue(())
1367 }
1368 }
1369}
1370
1371struct SearchInterfaceForPrivateItemsVisitor<'tcx> {
1377 tcx: TyCtxt<'tcx>,
1378 item_def_id: LocalDefId,
1379 required_visibility: ty::Visibility,
1381 required_effective_vis: Option<EffectiveVisibility>,
1382 hard_error: bool = false,
1383 in_primary_interface: bool = true,
1384 skip_assoc_tys: bool = false,
1385}
1386
1387impl SearchInterfaceForPrivateItemsVisitor<'_> {
1388 fn generics(&mut self) -> &mut Self {
1389 self.in_primary_interface = true;
1390 for param in &self.tcx.generics_of(self.item_def_id).own_params {
1391 if let GenericParamDefKind::Const { .. } = param.kind {
1392 let _ = self.visit(self.tcx.type_of(param.def_id).instantiate_identity());
1393 }
1394 if let Some(default) = param.default_value(self.tcx) {
1395 let _ = self.visit(default.instantiate_identity());
1396 }
1397 }
1398 self
1399 }
1400
1401 fn predicates(&mut self) -> &mut Self {
1402 self.in_primary_interface = false;
1403 let _ = self.visit_predicates(self.tcx.explicit_predicates_of(self.item_def_id));
1410 self
1411 }
1412
1413 fn bounds(&mut self) -> &mut Self {
1414 self.in_primary_interface = false;
1415 let _ = self.visit_clauses(self.tcx.explicit_item_bounds(self.item_def_id).skip_binder());
1416 self
1417 }
1418
1419 fn ty(&mut self) -> &mut Self {
1420 self.in_primary_interface = true;
1421 let _ = self.visit(self.tcx.type_of(self.item_def_id).instantiate_identity());
1422 self
1423 }
1424
1425 fn trait_ref(&mut self) -> &mut Self {
1426 self.in_primary_interface = true;
1427 let _ = self.visit_trait(self.tcx.impl_trait_ref(self.item_def_id).instantiate_identity());
1428 self
1429 }
1430
1431 fn check_def_id(&self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
1432 if self.leaks_private_dep(def_id) {
1433 self.tcx.emit_node_span_lint(
1434 lint::builtin::EXPORTED_PRIVATE_DEPENDENCIES,
1435 self.tcx.local_def_id_to_hir_id(self.item_def_id),
1436 self.tcx.def_span(self.item_def_id.to_def_id()),
1437 FromPrivateDependencyInPublicInterface {
1438 kind,
1439 descr: descr.into(),
1440 krate: self.tcx.crate_name(def_id.krate),
1441 },
1442 );
1443 }
1444
1445 let Some(local_def_id) = def_id.as_local() else {
1446 return false;
1447 };
1448
1449 let vis = self.tcx.local_visibility(local_def_id);
1450 if self.hard_error && !vis.is_at_least(self.required_visibility, self.tcx) {
1451 let vis_descr = match vis {
1452 ty::Visibility::Public => "public",
1453 ty::Visibility::Restricted(vis_def_id) => {
1454 if vis_def_id
1455 == self.tcx.parent_module_from_def_id(local_def_id).to_local_def_id()
1456 {
1457 "private"
1458 } else if vis_def_id.is_top_level_module() {
1459 "crate-private"
1460 } else {
1461 "restricted"
1462 }
1463 }
1464 };
1465
1466 let span = self.tcx.def_span(self.item_def_id.to_def_id());
1467 let vis_span = self.tcx.def_span(def_id);
1468 self.tcx.dcx().emit_err(InPublicInterface {
1469 span,
1470 vis_descr,
1471 kind,
1472 descr: descr.into(),
1473 vis_span,
1474 });
1475 return false;
1476 }
1477
1478 let Some(effective_vis) = self.required_effective_vis else {
1479 return false;
1480 };
1481
1482 let reachable_at_vis = *effective_vis.at_level(Level::Reachable);
1483
1484 if !vis.is_at_least(reachable_at_vis, self.tcx) {
1485 let lint = if self.in_primary_interface {
1486 lint::builtin::PRIVATE_INTERFACES
1487 } else {
1488 lint::builtin::PRIVATE_BOUNDS
1489 };
1490 let span = self.tcx.def_span(self.item_def_id.to_def_id());
1491 let vis_span = self.tcx.def_span(def_id);
1492 self.tcx.emit_node_span_lint(
1493 lint,
1494 self.tcx.local_def_id_to_hir_id(self.item_def_id),
1495 span,
1496 PrivateInterfacesOrBoundsLint {
1497 item_span: span,
1498 item_kind: self.tcx.def_descr(self.item_def_id.to_def_id()),
1499 item_descr: (&LazyDefPathStr {
1500 def_id: self.item_def_id.to_def_id(),
1501 tcx: self.tcx,
1502 })
1503 .into(),
1504 item_vis_descr: &reachable_at_vis.to_string(self.item_def_id, self.tcx),
1505 ty_span: vis_span,
1506 ty_kind: kind,
1507 ty_descr: descr.into(),
1508 ty_vis_descr: &vis.to_string(local_def_id, self.tcx),
1509 },
1510 );
1511 }
1512
1513 false
1514 }
1515
1516 fn leaks_private_dep(&self, item_id: DefId) -> bool {
1521 let ret = self.required_visibility.is_public() && self.tcx.is_private_dep(item_id.krate);
1522
1523 {
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:1523",
"rustc_privacy", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_privacy/src/lib.rs"),
::tracing_core::__macro_support::Option::Some(1523u32),
::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);
1524 ret
1525 }
1526}
1527
1528impl<'tcx> DefIdVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'tcx> {
1529 type Result = ControlFlow<()>;
1530 fn skip_assoc_tys(&self) -> bool {
1531 self.skip_assoc_tys
1532 }
1533 fn tcx(&self) -> TyCtxt<'tcx> {
1534 self.tcx
1535 }
1536 fn visit_def_id(
1537 &mut self,
1538 def_id: DefId,
1539 kind: &str,
1540 descr: &dyn fmt::Display,
1541 ) -> Self::Result {
1542 if self.check_def_id(def_id, kind, descr) {
1543 ControlFlow::Break(())
1544 } else {
1545 ControlFlow::Continue(())
1546 }
1547 }
1548}
1549
1550struct PrivateItemsInPublicInterfacesChecker<'a, 'tcx> {
1551 tcx: TyCtxt<'tcx>,
1552 effective_visibilities: &'a EffectiveVisibilities,
1553}
1554
1555impl<'tcx> PrivateItemsInPublicInterfacesChecker<'_, 'tcx> {
1556 fn check(
1557 &self,
1558 def_id: LocalDefId,
1559 required_visibility: ty::Visibility,
1560 required_effective_vis: Option<EffectiveVisibility>,
1561 ) -> SearchInterfaceForPrivateItemsVisitor<'tcx> {
1562 SearchInterfaceForPrivateItemsVisitor {
1563 tcx: self.tcx,
1564 item_def_id: def_id,
1565 required_visibility,
1566 required_effective_vis,
1567 ..
1568 }
1569 }
1570
1571 fn check_unnameable(&self, def_id: LocalDefId, effective_vis: Option<EffectiveVisibility>) {
1572 let Some(effective_vis) = effective_vis else {
1573 return;
1574 };
1575
1576 let reexported_at_vis = effective_vis.at_level(Level::Reexported);
1577 let reachable_at_vis = effective_vis.at_level(Level::Reachable);
1578
1579 if reachable_at_vis.is_public() && reexported_at_vis != reachable_at_vis {
1580 let hir_id = self.tcx.local_def_id_to_hir_id(def_id);
1581 let span = self.tcx.def_span(def_id.to_def_id());
1582 self.tcx.emit_node_span_lint(
1583 lint::builtin::UNNAMEABLE_TYPES,
1584 hir_id,
1585 span,
1586 UnnameableTypesLint {
1587 span,
1588 kind: self.tcx.def_descr(def_id.to_def_id()),
1589 descr: (&LazyDefPathStr { def_id: def_id.to_def_id(), tcx: self.tcx }).into(),
1590 reachable_vis: &reachable_at_vis.to_string(def_id, self.tcx),
1591 reexported_vis: &reexported_at_vis.to_string(def_id, self.tcx),
1592 },
1593 );
1594 }
1595 }
1596
1597 fn check_assoc_item(
1598 &self,
1599 item: &ty::AssocItem,
1600 vis: ty::Visibility,
1601 effective_vis: Option<EffectiveVisibility>,
1602 ) {
1603 let mut check = self.check(item.def_id.expect_local(), vis, effective_vis);
1604
1605 let is_assoc_ty = item.is_type();
1606 check.hard_error = is_assoc_ty;
1607 check.generics().predicates();
1608 if assoc_has_type_of(self.tcx, item) {
1609 check.ty();
1610 }
1611 if is_assoc_ty && item.container == AssocContainer::Trait {
1612 check.hard_error = false;
1615 check.bounds();
1616 }
1617 }
1618
1619 fn get(&self, def_id: LocalDefId) -> Option<EffectiveVisibility> {
1620 self.effective_visibilities.effective_vis(def_id).copied()
1621 }
1622
1623 fn check_item(&self, id: ItemId) {
1624 let tcx = self.tcx;
1625 let def_id = id.owner_id.def_id;
1626 let item_visibility = tcx.local_visibility(def_id);
1627 let effective_vis = self.get(def_id);
1628 let def_kind = tcx.def_kind(def_id);
1629
1630 match def_kind {
1631 DefKind::Const { .. } | DefKind::Static { .. } | DefKind::Fn | DefKind::TyAlias => {
1632 if let DefKind::TyAlias = def_kind {
1633 self.check_unnameable(def_id, effective_vis);
1634 }
1635 self.check(def_id, item_visibility, effective_vis).generics().predicates().ty();
1636 }
1637 DefKind::OpaqueTy => {
1638 self.check(def_id, item_visibility, effective_vis).generics().bounds();
1641 }
1642 DefKind::Trait => {
1643 self.check_unnameable(def_id, effective_vis);
1644
1645 self.check(def_id, item_visibility, effective_vis).generics().predicates();
1646
1647 for assoc_item in tcx.associated_items(id.owner_id).in_definition_order() {
1648 self.check_assoc_item(assoc_item, item_visibility, effective_vis);
1649 }
1650 }
1651 DefKind::TraitAlias => {
1652 self.check(def_id, item_visibility, effective_vis).generics().predicates();
1653 }
1654 DefKind::Enum => {
1655 self.check_unnameable(def_id, effective_vis);
1656 self.check(def_id, item_visibility, effective_vis).generics().predicates();
1657
1658 let adt = tcx.adt_def(id.owner_id);
1659 for field in adt.all_fields() {
1660 self.check(field.did.expect_local(), item_visibility, effective_vis).ty();
1661 }
1662 }
1663 DefKind::Struct | DefKind::Union => {
1665 self.check_unnameable(def_id, effective_vis);
1666 self.check(def_id, item_visibility, effective_vis).generics().predicates();
1667
1668 let adt = tcx.adt_def(id.owner_id);
1669 for field in adt.all_fields() {
1670 let visibility = min(item_visibility, field.vis.expect_local(), tcx);
1671 let field_ev = self.get(field.did.expect_local());
1672
1673 self.check(field.did.expect_local(), visibility, field_ev).ty();
1674 }
1675 }
1676 DefKind::ForeignMod => {}
1678 DefKind::Impl { of_trait } => {
1683 let impl_vis =
1684 ty::Visibility::of_impl::<false>(def_id, of_trait, tcx, &Default::default());
1685
1686 let impl_ev = EffectiveVisibility::of_impl::<false>(
1698 def_id,
1699 of_trait,
1700 tcx,
1701 self.effective_visibilities,
1702 );
1703
1704 let mut check = self.check(def_id, impl_vis, Some(impl_ev));
1705
1706 if !of_trait {
1709 check.generics().predicates();
1710 }
1711
1712 check.skip_assoc_tys = true;
1716 check.ty();
1717 if of_trait {
1718 check.trait_ref();
1719 }
1720
1721 for assoc_item in tcx.associated_items(id.owner_id).in_definition_order() {
1722 let impl_item_vis = if !of_trait {
1723 min(tcx.local_visibility(assoc_item.def_id.expect_local()), impl_vis, tcx)
1724 } else {
1725 impl_vis
1726 };
1727
1728 let impl_item_ev = if !of_trait {
1729 self.get(assoc_item.def_id.expect_local())
1730 .map(|ev| ev.min(impl_ev, self.tcx))
1731 } else {
1732 Some(impl_ev)
1733 };
1734
1735 self.check_assoc_item(assoc_item, impl_item_vis, impl_item_ev);
1736 }
1737 }
1738 _ => {}
1739 }
1740 }
1741
1742 fn check_foreign_item(&self, id: ForeignItemId) {
1743 let tcx = self.tcx;
1744 let def_id = id.owner_id.def_id;
1745 let item_visibility = tcx.local_visibility(def_id);
1746 let effective_vis = self.get(def_id);
1747
1748 if let DefKind::ForeignTy = self.tcx.def_kind(def_id) {
1749 self.check_unnameable(def_id, effective_vis);
1750 }
1751
1752 self.check(def_id, item_visibility, effective_vis).generics().predicates().ty();
1753 }
1754}
1755
1756pub fn provide(providers: &mut Providers) {
1757 *providers = Providers {
1758 effective_visibilities,
1759 check_private_in_public,
1760 check_mod_privacy,
1761 ..*providers
1762 };
1763}
1764
1765fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
1766 let mut visitor = NamePrivacyVisitor { tcx, maybe_typeck_results: None };
1768 tcx.hir_visit_item_likes_in_module(module_def_id, &mut visitor);
1769
1770 let span = tcx.def_span(module_def_id);
1773 let mut visitor = TypePrivacyVisitor { tcx, module_def_id, maybe_typeck_results: None, span };
1774
1775 let module = tcx.hir_module_items(module_def_id);
1776 for def_id in module.definitions() {
1777 let _ = rustc_ty_utils::sig_types::walk_types(tcx, def_id, &mut visitor);
1778
1779 if let Some(body_id) = tcx.hir_maybe_body_owned_by(def_id) {
1780 visitor.visit_nested_body(body_id.id());
1781 }
1782
1783 if let DefKind::Impl { of_trait: true } = tcx.def_kind(def_id) {
1784 let trait_ref = tcx.impl_trait_ref(def_id);
1785 let trait_ref = trait_ref.instantiate_identity();
1786 visitor.span =
1787 tcx.hir_expect_item(def_id).expect_impl().of_trait.unwrap().trait_ref.path.span;
1788 let _ =
1789 visitor.visit_def_id(trait_ref.def_id, "trait", &trait_ref.print_only_trait_path());
1790 }
1791 }
1792}
1793
1794fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities {
1795 let mut visitor = EmbargoVisitor {
1798 tcx,
1799 effective_visibilities: tcx.resolutions(()).effective_visibilities.clone(),
1800 macro_reachable: Default::default(),
1801 changed: false,
1802 };
1803
1804 visitor.effective_visibilities.check_invariants(tcx);
1805
1806 let impl_trait_pass = !tcx.sess.opts.actually_rustdoc;
1810 if impl_trait_pass {
1811 let krate = tcx.hir_crate_items(());
1814 for id in krate.opaques() {
1815 let opaque = tcx.hir_node_by_def_id(id).expect_opaque_ty();
1816 let should_visit = match opaque.origin {
1817 hir::OpaqueTyOrigin::FnReturn {
1818 parent,
1819 in_trait_or_impl: Some(hir::RpitContext::Trait),
1820 }
1821 | hir::OpaqueTyOrigin::AsyncFn {
1822 parent,
1823 in_trait_or_impl: Some(hir::RpitContext::Trait),
1824 } => match tcx.hir_node_by_def_id(parent).expect_trait_item().expect_fn().1 {
1825 hir::TraitFn::Required(_) => false,
1826 hir::TraitFn::Provided(..) => true,
1827 },
1828
1829 hir::OpaqueTyOrigin::FnReturn {
1832 in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
1833 ..
1834 }
1835 | hir::OpaqueTyOrigin::AsyncFn {
1836 in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
1837 ..
1838 }
1839 | hir::OpaqueTyOrigin::TyAlias { .. } => true,
1840 };
1841 if should_visit {
1842 let pub_ev = EffectiveVisibility::from_vis(ty::Visibility::Public);
1846 visitor
1847 .reach_through_impl_trait(opaque.def_id, pub_ev)
1848 .generics()
1849 .predicates()
1850 .ty();
1851 }
1852 }
1853
1854 visitor.changed = false;
1855 }
1856
1857 let crate_items = tcx.hir_crate_items(());
1858 loop {
1859 for id in crate_items.free_items() {
1860 visitor.check_def_id(id.owner_id);
1861 }
1862 for id in crate_items.foreign_items() {
1863 visitor.check_def_id(id.owner_id);
1864 }
1865 if visitor.changed {
1866 visitor.changed = false;
1867 } else {
1868 break;
1869 }
1870 }
1871 visitor.effective_visibilities.check_invariants(tcx);
1872
1873 let check_visitor =
1874 TestReachabilityVisitor { tcx, effective_visibilities: &visitor.effective_visibilities };
1875 for id in crate_items.owners() {
1876 check_visitor.check_def_id(id);
1877 }
1878
1879 tcx.arena.alloc(visitor.effective_visibilities)
1880}
1881
1882fn check_private_in_public(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
1883 let effective_visibilities = tcx.effective_visibilities(());
1884 let checker = PrivateItemsInPublicInterfacesChecker { tcx, effective_visibilities };
1886
1887 let crate_items = tcx.hir_module_items(module_def_id);
1888 let _ = crate_items.par_items(|id| Ok(checker.check_item(id)));
1889 let _ = crate_items.par_foreign_items(|id| Ok(checker.check_foreign_item(id)));
1890}