#![allow(internal_features)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
#![feature(associated_type_defaults)]
#![feature(let_chains)]
#![feature(rustdoc_internals)]
#![feature(try_blocks)]
#![warn(unreachable_pub)]
mod errors;
use std::fmt;
use std::marker::PhantomData;
use std::ops::ControlFlow;
use errors::{
FieldIsPrivate, FieldIsPrivateLabel, FromPrivateDependencyInPublicInterface, InPublicInterface,
ItemIsPrivate, PrivateInterfacesOrBoundsLint, ReportEffectiveVisibility, UnnameableTypesLint,
UnnamedItemIsPrivate,
};
use rustc_ast::MacroDef;
use rustc_ast::visit::{VisitorResult, try_visit};
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::intern::Interned;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId, LocalModDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{AssocItemKind, ForeignItemKind, ItemId, ItemKind, PatKind};
use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, Level};
use rustc_middle::query::Providers;
use rustc_middle::ty::print::PrintTraitRefExt as _;
use rustc_middle::ty::{
self, Const, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
TypeVisitor,
};
use rustc_middle::{bug, span_bug};
use rustc_session::lint;
use rustc_span::Span;
use rustc_span::hygiene::Transparency;
use rustc_span::symbol::{Ident, kw, sym};
use tracing::debug;
use {rustc_attr as attr, rustc_hir as hir};
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
struct LazyDefPathStr<'tcx> {
def_id: DefId,
tcx: TyCtxt<'tcx>,
}
impl<'tcx> fmt::Display for LazyDefPathStr<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.tcx.def_path_str(self.def_id))
}
}
pub trait DefIdVisitor<'tcx> {
type Result: VisitorResult = ();
const SHALLOW: bool = false;
const SKIP_ASSOC_TYS: bool = false;
fn tcx(&self) -> TyCtxt<'tcx>;
fn visit_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display)
-> Self::Result;
fn skeleton(&mut self) -> DefIdVisitorSkeleton<'_, 'tcx, Self> {
DefIdVisitorSkeleton {
def_id_visitor: self,
visited_opaque_tys: Default::default(),
dummy: Default::default(),
}
}
fn visit(&mut self, ty_fragment: impl TypeVisitable<TyCtxt<'tcx>>) -> Self::Result {
ty_fragment.visit_with(&mut self.skeleton())
}
fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> Self::Result {
self.skeleton().visit_trait(trait_ref)
}
fn visit_predicates(&mut self, predicates: ty::GenericPredicates<'tcx>) -> Self::Result {
self.skeleton().visit_clauses(predicates.predicates)
}
fn visit_clauses(&mut self, clauses: &[(ty::Clause<'tcx>, Span)]) -> Self::Result {
self.skeleton().visit_clauses(clauses)
}
}
pub struct DefIdVisitorSkeleton<'v, 'tcx, V: ?Sized> {
def_id_visitor: &'v mut V,
visited_opaque_tys: FxHashSet<DefId>,
dummy: PhantomData<TyCtxt<'tcx>>,
}
impl<'tcx, V> DefIdVisitorSkeleton<'_, 'tcx, V>
where
V: DefIdVisitor<'tcx> + ?Sized,
{
fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> V::Result {
let TraitRef { def_id, args, .. } = trait_ref;
try_visit!(self.def_id_visitor.visit_def_id(
def_id,
"trait",
&trait_ref.print_only_trait_path()
));
if V::SHALLOW { V::Result::output() } else { args.visit_with(self) }
}
fn visit_projection_term(&mut self, projection: ty::AliasTerm<'tcx>) -> V::Result {
let tcx = self.def_id_visitor.tcx();
let (trait_ref, assoc_args) = projection.trait_ref_and_own_args(tcx);
try_visit!(self.visit_trait(trait_ref));
if V::SHALLOW {
V::Result::output()
} else {
V::Result::from_branch(
assoc_args.iter().try_for_each(|arg| arg.visit_with(self).branch()),
)
}
}
fn visit_clause(&mut self, clause: ty::Clause<'tcx>) -> V::Result {
match clause.kind().skip_binder() {
ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity: _ }) => {
self.visit_trait(trait_ref)
}
ty::ClauseKind::HostEffect(pred) => {
try_visit!(self.visit_trait(pred.trait_ref));
pred.constness.visit_with(self)
}
ty::ClauseKind::Projection(ty::ProjectionPredicate {
projection_term: projection_ty,
term,
}) => {
try_visit!(term.visit_with(self));
self.visit_projection_term(projection_ty)
}
ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, _region)) => ty.visit_with(self),
ty::ClauseKind::RegionOutlives(..) => V::Result::output(),
ty::ClauseKind::ConstArgHasType(ct, ty) => {
try_visit!(ct.visit_with(self));
ty.visit_with(self)
}
ty::ClauseKind::ConstEvaluatable(ct) => ct.visit_with(self),
ty::ClauseKind::WellFormed(arg) => arg.visit_with(self),
}
}
fn visit_clauses(&mut self, clauses: &[(ty::Clause<'tcx>, Span)]) -> V::Result {
for &(clause, _) in clauses {
try_visit!(self.visit_clause(clause));
}
V::Result::output()
}
}
impl<'tcx, V> TypeVisitor<TyCtxt<'tcx>> for DefIdVisitorSkeleton<'_, 'tcx, V>
where
V: DefIdVisitor<'tcx> + ?Sized,
{
type Result = V::Result;
fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> Self::Result {
self.visit_clause(p.as_clause().unwrap())
}
fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
let tcx = self.def_id_visitor.tcx();
match *ty.kind() {
ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), ..)
| ty::Foreign(def_id)
| ty::FnDef(def_id, ..)
| ty::Closure(def_id, ..)
| ty::CoroutineClosure(def_id, ..)
| ty::Coroutine(def_id, ..) => {
try_visit!(self.def_id_visitor.visit_def_id(def_id, "type", &ty));
if V::SHALLOW {
return V::Result::output();
}
if let ty::FnDef(..) = ty.kind() {
try_visit!(tcx.fn_sig(def_id).instantiate_identity().visit_with(self));
}
if let Some(assoc_item) = tcx.opt_associated_item(def_id) {
if let Some(impl_def_id) = assoc_item.impl_container(tcx) {
try_visit!(
tcx.type_of(impl_def_id).instantiate_identity().visit_with(self)
);
}
}
}
ty::Alias(kind @ (ty::Inherent | ty::Weak | ty::Projection), data) => {
if V::SKIP_ASSOC_TYS {
return V::Result::output();
}
try_visit!(self.def_id_visitor.visit_def_id(
data.def_id,
match kind {
ty::Inherent | ty::Projection => "associated type",
ty::Weak => "type alias",
ty::Opaque => unreachable!(),
},
&LazyDefPathStr { def_id: data.def_id, tcx },
));
return if V::SHALLOW {
V::Result::output()
} else if kind == ty::Projection {
self.visit_projection_term(data.into())
} else {
V::Result::from_branch(
data.args.iter().try_for_each(|arg| arg.visit_with(self).branch()),
)
};
}
ty::Dynamic(predicates, ..) => {
for predicate in predicates {
let trait_ref = match predicate.skip_binder() {
ty::ExistentialPredicate::Trait(trait_ref) => trait_ref,
ty::ExistentialPredicate::Projection(proj) => proj.trait_ref(tcx),
ty::ExistentialPredicate::AutoTrait(def_id) => {
ty::ExistentialTraitRef::new(tcx, def_id, ty::GenericArgs::empty())
}
};
let ty::ExistentialTraitRef { def_id, .. } = trait_ref;
try_visit!(self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref));
}
}
ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
if self.visited_opaque_tys.insert(def_id) {
try_visit!(self.visit_clauses(tcx.explicit_item_bounds(def_id).skip_binder()));
}
}
ty::Bool
| ty::Char
| ty::Int(..)
| ty::Uint(..)
| ty::Float(..)
| ty::Str
| ty::Never
| ty::Array(..)
| ty::Slice(..)
| ty::Tuple(..)
| ty::RawPtr(..)
| ty::Ref(..)
| ty::Pat(..)
| ty::FnPtr(..)
| ty::Param(..)
| ty::Bound(..)
| ty::Error(_)
| ty::CoroutineWitness(..) => {}
ty::Placeholder(..) | ty::Infer(..) => {
bug!("unexpected type: {:?}", ty)
}
}
if V::SHALLOW { V::Result::output() } else { ty.super_visit_with(self) }
}
fn visit_const(&mut self, c: Const<'tcx>) -> Self::Result {
let tcx = self.def_id_visitor.tcx();
tcx.expand_abstract_consts(c).super_visit_with(self)
}
}
fn min(vis1: ty::Visibility, vis2: ty::Visibility, tcx: TyCtxt<'_>) -> ty::Visibility {
if vis1.is_at_least(vis2, tcx) { vis2 } else { vis1 }
}
struct FindMin<'a, 'tcx, VL: VisibilityLike, const SHALLOW: bool> {
tcx: TyCtxt<'tcx>,
effective_visibilities: &'a EffectiveVisibilities,
min: VL,
}
impl<'a, 'tcx, VL: VisibilityLike, const SHALLOW: bool> DefIdVisitor<'tcx>
for FindMin<'a, 'tcx, VL, SHALLOW>
{
const SHALLOW: bool = SHALLOW;
const SKIP_ASSOC_TYS: bool = true;
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
fn visit_def_id(&mut self, def_id: DefId, _kind: &str, _descr: &dyn fmt::Display) {
if let Some(def_id) = def_id.as_local() {
self.min = VL::new_min(self, def_id);
}
}
}
trait VisibilityLike: Sized {
const MAX: Self;
fn new_min<const SHALLOW: bool>(
find: &FindMin<'_, '_, Self, SHALLOW>,
def_id: LocalDefId,
) -> Self;
fn of_impl<const SHALLOW: bool>(
def_id: LocalDefId,
tcx: TyCtxt<'_>,
effective_visibilities: &EffectiveVisibilities,
) -> Self {
let mut find = FindMin::<_, SHALLOW> { tcx, effective_visibilities, min: Self::MAX };
find.visit(tcx.type_of(def_id).instantiate_identity());
if let Some(trait_ref) = tcx.impl_trait_ref(def_id) {
find.visit_trait(trait_ref.instantiate_identity());
}
find.min
}
}
impl VisibilityLike for ty::Visibility {
const MAX: Self = ty::Visibility::Public;
fn new_min<const SHALLOW: bool>(
find: &FindMin<'_, '_, Self, SHALLOW>,
def_id: LocalDefId,
) -> Self {
min(find.tcx.local_visibility(def_id), find.min, find.tcx)
}
}
impl VisibilityLike for EffectiveVisibility {
const MAX: Self = EffectiveVisibility::from_vis(ty::Visibility::Public);
fn new_min<const SHALLOW: bool>(
find: &FindMin<'_, '_, Self, SHALLOW>,
def_id: LocalDefId,
) -> Self {
let effective_vis =
find.effective_visibilities.effective_vis(def_id).copied().unwrap_or_else(|| {
let private_vis = ty::Visibility::Restricted(
find.tcx.parent_module_from_def_id(def_id).to_local_def_id(),
);
EffectiveVisibility::from_vis(private_vis)
});
effective_vis.min(find.min, find.tcx)
}
}
struct EmbargoVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
effective_visibilities: EffectiveVisibilities,
macro_reachable: FxHashSet<(LocalModDefId, LocalModDefId)>,
changed: bool,
}
struct ReachEverythingInTheInterfaceVisitor<'a, 'tcx> {
effective_vis: EffectiveVisibility,
item_def_id: LocalDefId,
ev: &'a mut EmbargoVisitor<'tcx>,
level: Level,
}
impl<'tcx> EmbargoVisitor<'tcx> {
fn get(&self, def_id: LocalDefId) -> Option<EffectiveVisibility> {
self.effective_visibilities.effective_vis(def_id).copied()
}
fn update(
&mut self,
def_id: LocalDefId,
inherited_effective_vis: EffectiveVisibility,
level: Level,
) {
let nominal_vis = self.tcx.local_visibility(def_id);
self.update_eff_vis(def_id, inherited_effective_vis, Some(nominal_vis), level);
}
fn update_eff_vis(
&mut self,
def_id: LocalDefId,
inherited_effective_vis: EffectiveVisibility,
max_vis: Option<ty::Visibility>,
level: Level,
) {
let private_vis =
ty::Visibility::Restricted(self.tcx.parent_module_from_def_id(def_id).into());
if max_vis != Some(private_vis) {
self.changed |= self.effective_visibilities.update(
def_id,
max_vis,
|| private_vis,
inherited_effective_vis,
level,
self.tcx,
);
}
}
fn reach(
&mut self,
def_id: LocalDefId,
effective_vis: EffectiveVisibility,
) -> ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
ReachEverythingInTheInterfaceVisitor {
effective_vis,
item_def_id: def_id,
ev: self,
level: Level::Reachable,
}
}
fn reach_through_impl_trait(
&mut self,
def_id: LocalDefId,
effective_vis: EffectiveVisibility,
) -> ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
ReachEverythingInTheInterfaceVisitor {
effective_vis,
item_def_id: def_id,
ev: self,
level: Level::ReachableThroughImplTrait,
}
}
fn update_reachability_from_macro(
&mut self,
local_def_id: LocalDefId,
md: &MacroDef,
macro_ev: EffectiveVisibility,
) {
let hir_id = self.tcx.local_def_id_to_hir_id(local_def_id);
let attrs = self.tcx.hir().attrs(hir_id);
if attr::find_transparency(attrs, md.macro_rules).0 != Transparency::Opaque {
return;
}
let macro_module_def_id = self.tcx.local_parent(local_def_id);
if self.tcx.def_kind(macro_module_def_id) != DefKind::Mod {
return;
}
let macro_module_def_id = LocalModDefId::new_unchecked(macro_module_def_id);
if self.effective_visibilities.public_at_level(local_def_id).is_none() {
return;
}
let mut module_def_id = macro_module_def_id;
loop {
let changed_reachability =
self.update_macro_reachable(module_def_id, macro_module_def_id, macro_ev);
if changed_reachability || module_def_id == LocalModDefId::CRATE_DEF_ID {
break;
}
module_def_id = LocalModDefId::new_unchecked(self.tcx.local_parent(module_def_id));
}
}
fn update_macro_reachable(
&mut self,
module_def_id: LocalModDefId,
defining_mod: LocalModDefId,
macro_ev: EffectiveVisibility,
) -> bool {
if self.macro_reachable.insert((module_def_id, defining_mod)) {
for child in self.tcx.module_children_local(module_def_id.to_local_def_id()) {
if let Res::Def(def_kind, def_id) = child.res
&& let Some(def_id) = def_id.as_local()
&& child.vis.is_accessible_from(defining_mod, self.tcx)
{
let vis = self.tcx.local_visibility(def_id);
self.update_macro_reachable_def(def_id, def_kind, vis, defining_mod, macro_ev);
}
}
true
} else {
false
}
}
fn update_macro_reachable_def(
&mut self,
def_id: LocalDefId,
def_kind: DefKind,
vis: ty::Visibility,
module: LocalModDefId,
macro_ev: EffectiveVisibility,
) {
self.update(def_id, macro_ev, Level::Reachable);
match def_kind {
DefKind::Const | DefKind::Static { .. } | DefKind::TraitAlias | DefKind::TyAlias => {
if vis.is_accessible_from(module, self.tcx) {
self.update(def_id, macro_ev, Level::Reachable);
}
}
DefKind::Macro(_) => {
let item = self.tcx.hir().expect_item(def_id);
if let hir::ItemKind::Macro(MacroDef { macro_rules: false, .. }, _) = item.kind {
if vis.is_accessible_from(module, self.tcx) {
self.update(def_id, macro_ev, Level::Reachable);
}
}
}
DefKind::Mod => {
if vis.is_accessible_from(module, self.tcx) {
self.update_macro_reachable(
LocalModDefId::new_unchecked(def_id),
module,
macro_ev,
);
}
}
DefKind::Struct | DefKind::Union => {
let item = self.tcx.hir().expect_item(def_id);
if let hir::ItemKind::Struct(ref struct_def, _)
| hir::ItemKind::Union(ref struct_def, _) = item.kind
{
for field in struct_def.fields() {
let field_vis = self.tcx.local_visibility(field.def_id);
if field_vis.is_accessible_from(module, self.tcx) {
self.reach(field.def_id, macro_ev).ty();
}
}
} else {
bug!("item {:?} with DefKind {:?}", item, def_kind);
}
}
DefKind::AssocConst
| DefKind::AssocTy
| DefKind::ConstParam
| DefKind::Ctor(_, _)
| DefKind::Enum
| DefKind::ForeignTy
| DefKind::Fn
| DefKind::OpaqueTy
| DefKind::AssocFn
| DefKind::Trait
| DefKind::TyParam
| DefKind::Variant
| DefKind::LifetimeParam
| DefKind::ExternCrate
| DefKind::Use
| DefKind::ForeignMod
| DefKind::AnonConst
| DefKind::InlineConst
| DefKind::Field
| DefKind::GlobalAsm
| DefKind::Impl { .. }
| DefKind::Closure
| DefKind::SyntheticCoroutineBody => (),
}
}
}
impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
let item_ev = self.get(item.owner_id.def_id);
match item.kind {
hir::ItemKind::Use(..)
| hir::ItemKind::ExternCrate(..)
| hir::ItemKind::GlobalAsm(..) => {}
hir::ItemKind::Mod(..) => {}
hir::ItemKind::Macro(macro_def, _) => {
if let Some(item_ev) = item_ev {
self.update_reachability_from_macro(item.owner_id.def_id, macro_def, item_ev);
}
}
hir::ItemKind::Const(..)
| hir::ItemKind::Static(..)
| hir::ItemKind::Fn(..)
| hir::ItemKind::TyAlias(..) => {
if let Some(item_ev) = item_ev {
self.reach(item.owner_id.def_id, item_ev).generics().predicates().ty();
}
}
hir::ItemKind::Trait(.., trait_item_refs) => {
if let Some(item_ev) = item_ev {
self.reach(item.owner_id.def_id, item_ev).generics().predicates();
for trait_item_ref in trait_item_refs {
self.update(trait_item_ref.id.owner_id.def_id, item_ev, Level::Reachable);
let tcx = self.tcx;
let mut reach = self.reach(trait_item_ref.id.owner_id.def_id, item_ev);
reach.generics().predicates();
if trait_item_ref.kind == AssocItemKind::Type
&& !tcx.defaultness(trait_item_ref.id.owner_id).has_value()
{
} else {
reach.ty();
}
}
}
}
hir::ItemKind::TraitAlias(..) => {
if let Some(item_ev) = item_ev {
self.reach(item.owner_id.def_id, item_ev).generics().predicates();
}
}
hir::ItemKind::Impl(impl_) => {
let item_ev = EffectiveVisibility::of_impl::<true>(
item.owner_id.def_id,
self.tcx,
&self.effective_visibilities,
);
self.update_eff_vis(item.owner_id.def_id, item_ev, None, Level::Direct);
self.reach(item.owner_id.def_id, item_ev).generics().predicates().ty().trait_ref();
for impl_item_ref in impl_.items {
let def_id = impl_item_ref.id.owner_id.def_id;
let max_vis =
impl_.of_trait.is_none().then(|| self.tcx.local_visibility(def_id));
self.update_eff_vis(def_id, item_ev, max_vis, Level::Direct);
if let Some(impl_item_ev) = self.get(def_id) {
self.reach(def_id, impl_item_ev).generics().predicates().ty();
}
}
}
hir::ItemKind::Enum(ref def, _) => {
if let Some(item_ev) = item_ev {
self.reach(item.owner_id.def_id, item_ev).generics().predicates();
}
for variant in def.variants {
if let Some(item_ev) = item_ev {
self.update(variant.def_id, item_ev, Level::Reachable);
}
if let Some(variant_ev) = self.get(variant.def_id) {
if let Some(ctor_def_id) = variant.data.ctor_def_id() {
self.update(ctor_def_id, variant_ev, Level::Reachable);
}
for field in variant.data.fields() {
self.update(field.def_id, variant_ev, Level::Reachable);
self.reach(field.def_id, variant_ev).ty();
}
self.reach(item.owner_id.def_id, variant_ev).ty();
}
if let Some(ctor_def_id) = variant.data.ctor_def_id() {
if let Some(ctor_ev) = self.get(ctor_def_id) {
self.reach(item.owner_id.def_id, ctor_ev).ty();
}
}
}
}
hir::ItemKind::ForeignMod { items, .. } => {
for foreign_item in items {
if let Some(foreign_item_ev) = self.get(foreign_item.id.owner_id.def_id) {
self.reach(foreign_item.id.owner_id.def_id, foreign_item_ev)
.generics()
.predicates()
.ty();
}
}
}
hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => {
if let Some(item_ev) = item_ev {
self.reach(item.owner_id.def_id, item_ev).generics().predicates();
for field in struct_def.fields() {
self.update(field.def_id, item_ev, Level::Reachable);
if let Some(field_ev) = self.get(field.def_id) {
self.reach(field.def_id, field_ev).ty();
}
}
}
if let Some(ctor_def_id) = struct_def.ctor_def_id() {
if let Some(item_ev) = item_ev {
self.update(ctor_def_id, item_ev, Level::Reachable);
}
if let Some(ctor_ev) = self.get(ctor_def_id) {
self.reach(item.owner_id.def_id, ctor_ev).ty();
}
}
}
}
}
}
impl ReachEverythingInTheInterfaceVisitor<'_, '_> {
fn generics(&mut self) -> &mut Self {
for param in &self.ev.tcx.generics_of(self.item_def_id).own_params {
if let GenericParamDefKind::Const { .. } = param.kind {
self.visit(self.ev.tcx.type_of(param.def_id).instantiate_identity());
}
if let Some(default) = param.default_value(self.ev.tcx) {
self.visit(default.instantiate_identity());
}
}
self
}
fn predicates(&mut self) -> &mut Self {
self.visit_predicates(self.ev.tcx.predicates_of(self.item_def_id));
self
}
fn ty(&mut self) -> &mut Self {
self.visit(self.ev.tcx.type_of(self.item_def_id).instantiate_identity());
self
}
fn trait_ref(&mut self) -> &mut Self {
if let Some(trait_ref) = self.ev.tcx.impl_trait_ref(self.item_def_id) {
self.visit_trait(trait_ref.instantiate_identity());
}
self
}
}
impl<'tcx> DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.ev.tcx
}
fn visit_def_id(&mut self, def_id: DefId, _kind: &str, _descr: &dyn fmt::Display) {
if let Some(def_id) = def_id.as_local() {
let max_vis = (self.level != Level::ReachableThroughImplTrait)
.then(|| self.ev.tcx.local_visibility(def_id));
self.ev.update_eff_vis(def_id, self.effective_vis, max_vis, self.level);
}
}
}
pub struct TestReachabilityVisitor<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
effective_visibilities: &'a EffectiveVisibilities,
}
impl<'a, 'tcx> TestReachabilityVisitor<'a, 'tcx> {
fn effective_visibility_diagnostic(&mut self, def_id: LocalDefId) {
if self.tcx.has_attr(def_id, sym::rustc_effective_visibility) {
let mut error_msg = String::new();
let span = self.tcx.def_span(def_id.to_def_id());
if let Some(effective_vis) = self.effective_visibilities.effective_vis(def_id) {
for level in Level::all_levels() {
let vis_str = effective_vis.at_level(level).to_string(def_id, self.tcx);
if level != Level::Direct {
error_msg.push_str(", ");
}
error_msg.push_str(&format!("{level:?}: {vis_str}"));
}
} else {
error_msg.push_str("not in the table");
}
self.tcx.dcx().emit_err(ReportEffectiveVisibility { span, descr: error_msg });
}
}
}
impl<'a, 'tcx> Visitor<'tcx> for TestReachabilityVisitor<'a, 'tcx> {
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
self.effective_visibility_diagnostic(item.owner_id.def_id);
match item.kind {
hir::ItemKind::Enum(ref def, _) => {
for variant in def.variants.iter() {
self.effective_visibility_diagnostic(variant.def_id);
if let Some(ctor_def_id) = variant.data.ctor_def_id() {
self.effective_visibility_diagnostic(ctor_def_id);
}
for field in variant.data.fields() {
self.effective_visibility_diagnostic(field.def_id);
}
}
}
hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => {
if let Some(ctor_def_id) = def.ctor_def_id() {
self.effective_visibility_diagnostic(ctor_def_id);
}
for field in def.fields() {
self.effective_visibility_diagnostic(field.def_id);
}
}
_ => {}
}
}
fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem<'tcx>) {
self.effective_visibility_diagnostic(item.owner_id.def_id);
}
fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem<'tcx>) {
self.effective_visibility_diagnostic(item.owner_id.def_id);
}
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
self.effective_visibility_diagnostic(item.owner_id.def_id);
}
}
struct NamePrivacyVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
}
impl<'tcx> NamePrivacyVisitor<'tcx> {
#[track_caller]
fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> {
self.maybe_typeck_results
.expect("`NamePrivacyVisitor::typeck_results` called outside of body")
}
fn check_field(
&mut self,
hir_id: hir::HirId, use_ctxt: Span, span: Span, def: ty::AdtDef<'tcx>, field: &'tcx ty::FieldDef,
in_update_syntax: bool,
) {
if def.is_enum() {
return;
}
let ident = Ident::new(kw::Empty, use_ctxt);
let def_id = self.tcx.adjust_ident_and_get_scope(ident, def.did(), hir_id).1;
if !field.vis.is_accessible_from(def_id, self.tcx) {
self.tcx.dcx().emit_err(FieldIsPrivate {
span,
field_name: field.name,
variant_descr: def.variant_descr(),
def_path_str: self.tcx.def_path_str(def.did()),
label: if in_update_syntax {
FieldIsPrivateLabel::IsUpdateSyntax { span, field_name: field.name }
} else {
FieldIsPrivateLabel::Other { span }
},
});
}
}
}
impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> {
fn visit_nested_body(&mut self, body_id: hir::BodyId) {
let new_typeck_results = self.tcx.typeck_body(body_id);
if new_typeck_results.tainted_by_errors.is_some() {
return;
}
let old_maybe_typeck_results = self.maybe_typeck_results.replace(new_typeck_results);
self.visit_body(self.tcx.hir().body(body_id));
self.maybe_typeck_results = old_maybe_typeck_results;
}
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
if let hir::ExprKind::Struct(qpath, fields, ref base) = expr.kind {
let res = self.typeck_results().qpath_res(qpath, expr.hir_id);
let adt = self.typeck_results().expr_ty(expr).ty_adt_def().unwrap();
let variant = adt.variant_of_res(res);
if let Some(base) = *base {
for (vf_index, variant_field) in variant.fields.iter_enumerated() {
let field = fields
.iter()
.find(|f| self.typeck_results().field_index(f.hir_id) == vf_index);
let (hir_id, use_ctxt, span) = match field {
Some(field) => (field.hir_id, field.ident.span, field.span),
None => (base.hir_id, base.span, base.span),
};
self.check_field(hir_id, use_ctxt, span, adt, variant_field, true);
}
} else {
for field in fields {
let (hir_id, use_ctxt, span) = (field.hir_id, field.ident.span, field.span);
let index = self.typeck_results().field_index(field.hir_id);
self.check_field(hir_id, use_ctxt, span, adt, &variant.fields[index], false);
}
}
}
intravisit::walk_expr(self, expr);
}
fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) {
if let PatKind::Struct(ref qpath, fields, _) = pat.kind {
let res = self.typeck_results().qpath_res(qpath, pat.hir_id);
let adt = self.typeck_results().pat_ty(pat).ty_adt_def().unwrap();
let variant = adt.variant_of_res(res);
for field in fields {
let (hir_id, use_ctxt, span) = (field.hir_id, field.ident.span, field.span);
let index = self.typeck_results().field_index(field.hir_id);
self.check_field(hir_id, use_ctxt, span, adt, &variant.fields[index], false);
}
}
intravisit::walk_pat(self, pat);
}
}
struct TypePrivacyVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
module_def_id: LocalModDefId,
maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
span: Span,
}
impl<'tcx> TypePrivacyVisitor<'tcx> {
fn item_is_accessible(&self, did: DefId) -> bool {
self.tcx.visibility(did).is_accessible_from(self.module_def_id, self.tcx)
}
fn check_expr_pat_type(&mut self, id: hir::HirId, span: Span) -> bool {
self.span = span;
let typeck_results = self
.maybe_typeck_results
.unwrap_or_else(|| span_bug!(span, "`hir::Expr` or `hir::Pat` outside of a body"));
let result: ControlFlow<()> = try {
self.visit(typeck_results.node_type(id))?;
self.visit(typeck_results.node_args(id))?;
if let Some(adjustments) = typeck_results.adjustments().get(id) {
adjustments.iter().try_for_each(|adjustment| self.visit(adjustment.target))?;
}
};
result.is_break()
}
fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
let is_error = !self.item_is_accessible(def_id);
if is_error {
self.tcx.dcx().emit_err(ItemIsPrivate { span: self.span, kind, descr: descr.into() });
}
is_error
}
}
impl<'tcx> rustc_ty_utils::sig_types::SpannedTypeVisitor<'tcx> for TypePrivacyVisitor<'tcx> {
type Result = ControlFlow<()>;
fn visit(&mut self, span: Span, value: impl TypeVisitable<TyCtxt<'tcx>>) -> Self::Result {
self.span = span;
value.visit_with(&mut self.skeleton())
}
}
impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
fn visit_nested_body(&mut self, body_id: hir::BodyId) {
let old_maybe_typeck_results =
self.maybe_typeck_results.replace(self.tcx.typeck_body(body_id));
self.visit_body(self.tcx.hir().body(body_id));
self.maybe_typeck_results = old_maybe_typeck_results;
}
fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty<'tcx>) {
self.span = hir_ty.span;
if self
.visit(
self.maybe_typeck_results
.unwrap_or_else(|| span_bug!(hir_ty.span, "`hir::Ty` outside of a body"))
.node_type(hir_ty.hir_id),
)
.is_break()
{
return;
}
intravisit::walk_ty(self, hir_ty);
}
fn visit_infer(&mut self, inf: &'tcx hir::InferArg) {
self.span = inf.span;
if let Some(ty) = self
.maybe_typeck_results
.unwrap_or_else(|| span_bug!(inf.span, "`hir::InferArg` outside of a body"))
.node_type_opt(inf.hir_id)
{
if self.visit(ty).is_break() {
return;
}
} else {
}
intravisit::walk_inf(self, inf);
}
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
if self.check_expr_pat_type(expr.hir_id, expr.span) {
return;
}
match expr.kind {
hir::ExprKind::Assign(_, rhs, _) | hir::ExprKind::Match(rhs, ..) => {
if self.check_expr_pat_type(rhs.hir_id, rhs.span) {
return;
}
}
hir::ExprKind::MethodCall(segment, ..) => {
self.span = segment.ident.span;
let typeck_results = self
.maybe_typeck_results
.unwrap_or_else(|| span_bug!(self.span, "`hir::Expr` outside of a body"));
if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) {
if self.visit(self.tcx.type_of(def_id).instantiate_identity()).is_break() {
return;
}
} else {
self.tcx
.dcx()
.span_delayed_bug(expr.span, "no type-dependent def for method call");
}
}
_ => {}
}
intravisit::walk_expr(self, expr);
}
fn visit_qpath(&mut self, qpath: &'tcx hir::QPath<'tcx>, id: hir::HirId, span: Span) {
let def = match qpath {
hir::QPath::Resolved(_, path) => match path.res {
Res::Def(kind, def_id) => Some((kind, def_id)),
_ => None,
},
hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => {
match self.maybe_typeck_results {
Some(typeck_results) => typeck_results.type_dependent_def(id),
None => None,
}
}
};
let def = def.filter(|(kind, _)| {
matches!(
kind,
DefKind::AssocFn | DefKind::AssocConst | DefKind::AssocTy | DefKind::Static { .. }
)
});
if let Some((kind, def_id)) = def {
let is_local_static =
if let DefKind::Static { .. } = kind { def_id.is_local() } else { false };
if !self.item_is_accessible(def_id) && !is_local_static {
let name = match *qpath {
hir::QPath::LangItem(it, ..) => {
self.tcx.lang_items().get(it).map(|did| self.tcx.def_path_str(did))
}
hir::QPath::Resolved(_, path) => Some(self.tcx.def_path_str(path.res.def_id())),
hir::QPath::TypeRelative(_, segment) => Some(segment.ident.to_string()),
};
let kind = self.tcx.def_descr(def_id);
let sess = self.tcx.sess;
let _ = match name {
Some(name) => {
sess.dcx().emit_err(ItemIsPrivate { span, kind, descr: (&name).into() })
}
None => sess.dcx().emit_err(UnnamedItemIsPrivate { span, kind }),
};
return;
}
}
intravisit::walk_qpath(self, qpath, id);
}
fn visit_pat(&mut self, pattern: &'tcx hir::Pat<'tcx>) {
if self.check_expr_pat_type(pattern.hir_id, pattern.span) {
return;
}
intravisit::walk_pat(self, pattern);
}
fn visit_local(&mut self, local: &'tcx hir::LetStmt<'tcx>) {
if let Some(init) = local.init {
if self.check_expr_pat_type(init.hir_id, init.span) {
return;
}
}
intravisit::walk_local(self, local);
}
}
impl<'tcx> DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> {
type Result = ControlFlow<()>;
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
fn visit_def_id(
&mut self,
def_id: DefId,
kind: &str,
descr: &dyn fmt::Display,
) -> Self::Result {
if self.check_def_id(def_id, kind, descr) {
ControlFlow::Break(())
} else {
ControlFlow::Continue(())
}
}
}
struct SearchInterfaceForPrivateItemsVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
item_def_id: LocalDefId,
required_visibility: ty::Visibility,
required_effective_vis: Option<EffectiveVisibility>,
in_assoc_ty: bool,
in_primary_interface: bool,
}
impl SearchInterfaceForPrivateItemsVisitor<'_> {
fn generics(&mut self) -> &mut Self {
self.in_primary_interface = true;
for param in &self.tcx.generics_of(self.item_def_id).own_params {
match param.kind {
GenericParamDefKind::Lifetime => {}
GenericParamDefKind::Type { has_default, .. } => {
if has_default {
self.visit(self.tcx.type_of(param.def_id).instantiate_identity());
}
}
GenericParamDefKind::Const { .. } => {
self.visit(self.tcx.type_of(param.def_id).instantiate_identity());
}
}
}
self
}
fn predicates(&mut self) -> &mut Self {
self.in_primary_interface = false;
self.visit_predicates(self.tcx.explicit_predicates_of(self.item_def_id));
self
}
fn bounds(&mut self) -> &mut Self {
self.in_primary_interface = false;
self.visit_clauses(self.tcx.explicit_item_bounds(self.item_def_id).skip_binder());
self
}
fn ty(&mut self) -> &mut Self {
self.in_primary_interface = true;
self.visit(self.tcx.type_of(self.item_def_id).instantiate_identity());
self
}
fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
if self.leaks_private_dep(def_id) {
self.tcx.emit_node_span_lint(
lint::builtin::EXPORTED_PRIVATE_DEPENDENCIES,
self.tcx.local_def_id_to_hir_id(self.item_def_id),
self.tcx.def_span(self.item_def_id.to_def_id()),
FromPrivateDependencyInPublicInterface {
kind,
descr: descr.into(),
krate: self.tcx.crate_name(def_id.krate),
},
);
}
let Some(local_def_id) = def_id.as_local() else {
return false;
};
let vis = self.tcx.local_visibility(local_def_id);
let span = self.tcx.def_span(self.item_def_id.to_def_id());
let vis_span = self.tcx.def_span(def_id);
if self.in_assoc_ty && !vis.is_at_least(self.required_visibility, self.tcx) {
let vis_descr = match vis {
ty::Visibility::Public => "public",
ty::Visibility::Restricted(vis_def_id) => {
if vis_def_id
== self.tcx.parent_module_from_def_id(local_def_id).to_local_def_id()
{
"private"
} else if vis_def_id.is_top_level_module() {
"crate-private"
} else {
"restricted"
}
}
};
self.tcx.dcx().emit_err(InPublicInterface {
span,
vis_descr,
kind,
descr: descr.into(),
vis_span,
});
return false;
}
let Some(effective_vis) = self.required_effective_vis else {
return false;
};
let reachable_at_vis = *effective_vis.at_level(Level::Reachable);
if !vis.is_at_least(reachable_at_vis, self.tcx) {
let lint = if self.in_primary_interface {
lint::builtin::PRIVATE_INTERFACES
} else {
lint::builtin::PRIVATE_BOUNDS
};
self.tcx.emit_node_span_lint(
lint,
self.tcx.local_def_id_to_hir_id(self.item_def_id),
span,
PrivateInterfacesOrBoundsLint {
item_span: span,
item_kind: self.tcx.def_descr(self.item_def_id.to_def_id()),
item_descr: (&LazyDefPathStr {
def_id: self.item_def_id.to_def_id(),
tcx: self.tcx,
})
.into(),
item_vis_descr: &reachable_at_vis.to_string(self.item_def_id, self.tcx),
ty_span: vis_span,
ty_kind: kind,
ty_descr: descr.into(),
ty_vis_descr: &vis.to_string(local_def_id, self.tcx),
},
);
}
false
}
fn leaks_private_dep(&self, item_id: DefId) -> bool {
let ret = self.required_visibility.is_public() && self.tcx.is_private_dep(item_id.krate);
debug!("leaks_private_dep(item_id={:?})={}", item_id, ret);
ret
}
}
impl<'tcx> DefIdVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'tcx> {
type Result = ControlFlow<()>;
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
fn visit_def_id(
&mut self,
def_id: DefId,
kind: &str,
descr: &dyn fmt::Display,
) -> Self::Result {
if self.check_def_id(def_id, kind, descr) {
ControlFlow::Break(())
} else {
ControlFlow::Continue(())
}
}
}
struct PrivateItemsInPublicInterfacesChecker<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
effective_visibilities: &'a EffectiveVisibilities,
}
impl<'tcx> PrivateItemsInPublicInterfacesChecker<'_, 'tcx> {
fn check(
&self,
def_id: LocalDefId,
required_visibility: ty::Visibility,
required_effective_vis: Option<EffectiveVisibility>,
) -> SearchInterfaceForPrivateItemsVisitor<'tcx> {
SearchInterfaceForPrivateItemsVisitor {
tcx: self.tcx,
item_def_id: def_id,
required_visibility,
required_effective_vis,
in_assoc_ty: false,
in_primary_interface: true,
}
}
fn check_unnameable(&self, def_id: LocalDefId, effective_vis: Option<EffectiveVisibility>) {
let Some(effective_vis) = effective_vis else {
return;
};
let reexported_at_vis = effective_vis.at_level(Level::Reexported);
let reachable_at_vis = effective_vis.at_level(Level::Reachable);
if reachable_at_vis.is_public() && reexported_at_vis != reachable_at_vis {
let hir_id = self.tcx.local_def_id_to_hir_id(def_id);
let span = self.tcx.def_span(def_id.to_def_id());
self.tcx.emit_node_span_lint(
lint::builtin::UNNAMEABLE_TYPES,
hir_id,
span,
UnnameableTypesLint {
span,
kind: self.tcx.def_descr(def_id.to_def_id()),
descr: (&LazyDefPathStr { def_id: def_id.to_def_id(), tcx: self.tcx }).into(),
reachable_vis: &reachable_at_vis.to_string(def_id, self.tcx),
reexported_vis: &reexported_at_vis.to_string(def_id, self.tcx),
},
);
}
}
fn check_assoc_item(
&self,
def_id: LocalDefId,
assoc_item_kind: AssocItemKind,
vis: ty::Visibility,
effective_vis: Option<EffectiveVisibility>,
) {
let mut check = self.check(def_id, vis, effective_vis);
let (check_ty, is_assoc_ty) = match assoc_item_kind {
AssocItemKind::Const | AssocItemKind::Fn { .. } => (true, false),
AssocItemKind::Type => (self.tcx.defaultness(def_id).has_value(), true),
};
check.in_assoc_ty = is_assoc_ty;
check.generics().predicates();
if check_ty {
check.ty();
}
}
fn get(&self, def_id: LocalDefId) -> Option<EffectiveVisibility> {
self.effective_visibilities.effective_vis(def_id).copied()
}
fn check_item(&mut self, id: ItemId) {
let tcx = self.tcx;
let def_id = id.owner_id.def_id;
let item_visibility = tcx.local_visibility(def_id);
let effective_vis = self.get(def_id);
let def_kind = tcx.def_kind(def_id);
match def_kind {
DefKind::Const | DefKind::Static { .. } | DefKind::Fn | DefKind::TyAlias => {
if let DefKind::TyAlias = def_kind {
self.check_unnameable(def_id, effective_vis);
}
self.check(def_id, item_visibility, effective_vis).generics().predicates().ty();
}
DefKind::OpaqueTy => {
self.check(def_id, item_visibility, effective_vis).generics().bounds();
}
DefKind::Trait => {
let item = tcx.hir().item(id);
if let hir::ItemKind::Trait(.., trait_item_refs) = item.kind {
self.check_unnameable(item.owner_id.def_id, effective_vis);
self.check(item.owner_id.def_id, item_visibility, effective_vis)
.generics()
.predicates();
for trait_item_ref in trait_item_refs {
self.check_assoc_item(
trait_item_ref.id.owner_id.def_id,
trait_item_ref.kind,
item_visibility,
effective_vis,
);
if let AssocItemKind::Type = trait_item_ref.kind {
self.check(
trait_item_ref.id.owner_id.def_id,
item_visibility,
effective_vis,
)
.bounds();
}
}
}
}
DefKind::TraitAlias => {
self.check(def_id, item_visibility, effective_vis).generics().predicates();
}
DefKind::Enum => {
let item = tcx.hir().item(id);
if let hir::ItemKind::Enum(ref def, _) = item.kind {
self.check_unnameable(item.owner_id.def_id, effective_vis);
self.check(item.owner_id.def_id, item_visibility, effective_vis)
.generics()
.predicates();
for variant in def.variants {
for field in variant.data.fields() {
self.check(field.def_id, item_visibility, effective_vis).ty();
}
}
}
}
DefKind::ForeignMod => {
let item = tcx.hir().item(id);
if let hir::ItemKind::ForeignMod { items, .. } = item.kind {
for foreign_item in items {
let foreign_item = tcx.hir().foreign_item(foreign_item.id);
let ev = self.get(foreign_item.owner_id.def_id);
let vis = tcx.local_visibility(foreign_item.owner_id.def_id);
if let ForeignItemKind::Type = foreign_item.kind {
self.check_unnameable(foreign_item.owner_id.def_id, ev);
}
self.check(foreign_item.owner_id.def_id, vis, ev)
.generics()
.predicates()
.ty();
}
}
}
DefKind::Struct | DefKind::Union => {
let item = tcx.hir().item(id);
if let hir::ItemKind::Struct(ref struct_def, _)
| hir::ItemKind::Union(ref struct_def, _) = item.kind
{
self.check_unnameable(item.owner_id.def_id, effective_vis);
self.check(item.owner_id.def_id, item_visibility, effective_vis)
.generics()
.predicates();
for field in struct_def.fields() {
let field_visibility = tcx.local_visibility(field.def_id);
let field_ev = self.get(field.def_id);
self.check(
field.def_id,
min(item_visibility, field_visibility, tcx),
field_ev,
)
.ty();
}
}
}
DefKind::Impl { .. } => {
let item = tcx.hir().item(id);
if let hir::ItemKind::Impl(impl_) = item.kind {
let impl_vis = ty::Visibility::of_impl::<false>(
item.owner_id.def_id,
tcx,
&Default::default(),
);
let impl_ev = EffectiveVisibility::of_impl::<false>(
item.owner_id.def_id,
tcx,
self.effective_visibilities,
);
if impl_.of_trait.is_none() {
self.check(item.owner_id.def_id, impl_vis, Some(impl_ev))
.generics()
.predicates();
}
for impl_item_ref in impl_.items {
let impl_item_vis = if impl_.of_trait.is_none() {
min(
tcx.local_visibility(impl_item_ref.id.owner_id.def_id),
impl_vis,
tcx,
)
} else {
impl_vis
};
let impl_item_ev = if impl_.of_trait.is_none() {
self.get(impl_item_ref.id.owner_id.def_id)
.map(|ev| ev.min(impl_ev, self.tcx))
} else {
Some(impl_ev)
};
self.check_assoc_item(
impl_item_ref.id.owner_id.def_id,
impl_item_ref.kind,
impl_item_vis,
impl_item_ev,
);
}
}
}
_ => {}
}
}
}
pub fn provide(providers: &mut Providers) {
*providers = Providers {
effective_visibilities,
check_private_in_public,
check_mod_privacy,
..*providers
};
}
fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
let mut visitor = NamePrivacyVisitor { tcx, maybe_typeck_results: None };
tcx.hir().visit_item_likes_in_module(module_def_id, &mut visitor);
let span = tcx.def_span(module_def_id);
let mut visitor = TypePrivacyVisitor { tcx, module_def_id, maybe_typeck_results: None, span };
let module = tcx.hir_module_items(module_def_id);
for def_id in module.definitions() {
rustc_ty_utils::sig_types::walk_types(tcx, def_id, &mut visitor);
if let Some(body_id) = tcx.hir().maybe_body_owned_by(def_id) {
visitor.visit_nested_body(body_id.id());
}
}
for id in module.free_items() {
if let ItemKind::Impl(i) = tcx.hir().item(id).kind {
if let Some(item) = i.of_trait {
let trait_ref = tcx.impl_trait_ref(id.owner_id.def_id).unwrap();
let trait_ref = trait_ref.instantiate_identity();
visitor.span = item.path.span;
visitor.visit_def_id(trait_ref.def_id, "trait", &trait_ref.print_only_trait_path());
}
}
}
}
fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities {
let mut visitor = EmbargoVisitor {
tcx,
effective_visibilities: tcx.resolutions(()).effective_visibilities.clone(),
macro_reachable: Default::default(),
changed: false,
};
visitor.effective_visibilities.check_invariants(tcx);
let impl_trait_pass = !tcx.sess.opts.actually_rustdoc;
if impl_trait_pass {
let krate = tcx.hir_crate_items(());
for id in krate.opaques() {
let opaque = tcx.hir_node_by_def_id(id).expect_opaque_ty();
let should_visit = match opaque.origin {
hir::OpaqueTyOrigin::FnReturn {
parent,
in_trait_or_impl: Some(hir::RpitContext::Trait),
}
| hir::OpaqueTyOrigin::AsyncFn {
parent,
in_trait_or_impl: Some(hir::RpitContext::Trait),
} => match tcx.hir_node_by_def_id(parent).expect_trait_item().expect_fn().1 {
hir::TraitFn::Required(_) => false,
hir::TraitFn::Provided(..) => true,
},
hir::OpaqueTyOrigin::FnReturn {
in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
..
}
| hir::OpaqueTyOrigin::AsyncFn {
in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
..
}
| hir::OpaqueTyOrigin::TyAlias { .. } => true,
};
if should_visit {
let pub_ev = EffectiveVisibility::from_vis(ty::Visibility::Public);
visitor
.reach_through_impl_trait(opaque.def_id, pub_ev)
.generics()
.predicates()
.ty();
}
}
visitor.changed = false;
}
loop {
tcx.hir().visit_all_item_likes_in_crate(&mut visitor);
if visitor.changed {
visitor.changed = false;
} else {
break;
}
}
visitor.effective_visibilities.check_invariants(tcx);
let mut check_visitor =
TestReachabilityVisitor { tcx, effective_visibilities: &visitor.effective_visibilities };
check_visitor.effective_visibility_diagnostic(CRATE_DEF_ID);
tcx.hir().visit_all_item_likes_in_crate(&mut check_visitor);
tcx.arena.alloc(visitor.effective_visibilities)
}
fn check_private_in_public(tcx: TyCtxt<'_>, (): ()) {
let effective_visibilities = tcx.effective_visibilities(());
let mut checker = PrivateItemsInPublicInterfacesChecker { tcx, effective_visibilities };
for id in tcx.hir().items() {
checker.check_item(id);
}
}