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