1 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
2 #![feature(in_band_lifetimes)]
4 #![recursion_limit = "256"]
6 use rustc_attr
as attr
;
7 use rustc_data_structures
::fx
::FxHashSet
;
8 use rustc_errors
::struct_span_err
;
10 use rustc_hir
::def
::{DefKind, Res}
;
11 use rustc_hir
::def_id
::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}
;
12 use rustc_hir
::intravisit
::{self, DeepVisitor, NestedVisitorMap, Visitor}
;
13 use rustc_hir
::{AssocItemKind, HirIdSet, Node, PatKind}
;
14 use rustc_middle
::bug
;
15 use rustc_middle
::hir
::map
::Map
;
16 use rustc_middle
::middle
::privacy
::{AccessLevel, AccessLevels}
;
17 use rustc_middle
::ty
::fold
::TypeVisitor
;
18 use rustc_middle
::ty
::query
::Providers
;
19 use rustc_middle
::ty
::subst
::InternalSubsts
;
20 use rustc_middle
::ty
::{self, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeFoldable}
;
21 use rustc_session
::lint
;
22 use rustc_span
::hygiene
::Transparency
;
23 use rustc_span
::symbol
::{kw, sym, Ident}
;
26 use std
::marker
::PhantomData
;
27 use std
::{cmp, fmt, mem}
;
29 ////////////////////////////////////////////////////////////////////////////////
30 /// Generic infrastructure used to implement specific visitors below.
31 ////////////////////////////////////////////////////////////////////////////////
33 /// Implemented to visit all `DefId`s in a type.
34 /// Visiting `DefId`s is useful because visibilities and reachabilities are attached to them.
35 /// The idea is to visit "all components of a type", as documented in
36 /// https://github.com/rust-lang/rfcs/blob/master/text/2145-type-privacy.md#how-to-determine-visibility-of-a-type.
37 /// The default type visitor (`TypeVisitor`) does most of the job, but it has some shortcomings.
38 /// First, it doesn't have overridable `fn visit_trait_ref`, so we have to catch trait `DefId`s
39 /// manually. Second, it doesn't visit some type components like signatures of fn types, or traits
40 /// in `impl Trait`, see individual comments in `DefIdVisitorSkeleton::visit_ty`.
41 trait DefIdVisitor
<'tcx
> {
42 fn tcx(&self) -> TyCtxt
<'tcx
>;
43 fn shallow(&self) -> bool
{
46 fn skip_assoc_tys(&self) -> bool
{
49 fn visit_def_id(&mut self, def_id
: DefId
, kind
: &str, descr
: &dyn fmt
::Display
) -> bool
;
51 /// Not overridden, but used to actually visit types and traits.
52 fn skeleton(&mut self) -> DefIdVisitorSkeleton
<'_
, 'tcx
, Self> {
53 DefIdVisitorSkeleton
{
55 visited_opaque_tys
: Default
::default(),
56 dummy
: Default
::default(),
59 fn visit(&mut self, ty_fragment
: impl TypeFoldable
<'tcx
>) -> bool
{
60 ty_fragment
.visit_with(&mut self.skeleton())
62 fn visit_trait(&mut self, trait_ref
: TraitRef
<'tcx
>) -> bool
{
63 self.skeleton().visit_trait(trait_ref
)
65 fn visit_predicates(&mut self, predicates
: ty
::GenericPredicates
<'tcx
>) -> bool
{
66 self.skeleton().visit_predicates(predicates
)
70 struct DefIdVisitorSkeleton
<'v
, 'tcx
, V
: ?Sized
> {
71 def_id_visitor
: &'v
mut V
,
72 visited_opaque_tys
: FxHashSet
<DefId
>,
73 dummy
: PhantomData
<TyCtxt
<'tcx
>>,
76 impl<'tcx
, V
> DefIdVisitorSkeleton
<'_
, 'tcx
, V
>
78 V
: DefIdVisitor
<'tcx
> + ?Sized
,
80 fn visit_trait(&mut self, trait_ref
: TraitRef
<'tcx
>) -> bool
{
81 let TraitRef { def_id, substs }
= trait_ref
;
82 self.def_id_visitor
.visit_def_id(def_id
, "trait", &trait_ref
.print_only_trait_path())
83 || (!self.def_id_visitor
.shallow() && substs
.visit_with(self))
86 fn visit_predicate(&mut self, predicate
: ty
::Predicate
<'tcx
>) -> bool
{
87 match predicate
.skip_binders() {
88 ty
::PredicateAtom
::Trait(ty
::TraitPredicate { trait_ref }
, _
) => {
89 self.visit_trait(trait_ref
)
91 ty
::PredicateAtom
::Projection(ty
::ProjectionPredicate { projection_ty, ty }
) => {
93 || self.visit_trait(projection_ty
.trait_ref(self.def_id_visitor
.tcx()))
95 ty
::PredicateAtom
::TypeOutlives(ty
::OutlivesPredicate(ty
, _region
)) => {
98 ty
::PredicateAtom
::RegionOutlives(..) => false,
99 ty
::PredicateAtom
::ConstEvaluatable(..)
100 if self.def_id_visitor
.tcx().features().const_evaluatable_checked
=>
102 // FIXME(const_evaluatable_checked): If the constant used here depends on a
103 // private function we may have to do something here...
105 // For now, let's just pretend that everything is fine.
108 _
=> bug
!("unexpected predicate: {:?}", predicate
),
112 fn visit_predicates(&mut self, predicates
: ty
::GenericPredicates
<'tcx
>) -> bool
{
113 let ty
::GenericPredicates { parent: _, predicates }
= predicates
;
114 for &(predicate
, _span
) in predicates
{
115 if self.visit_predicate(predicate
) {
123 impl<'tcx
, V
> TypeVisitor
<'tcx
> for DefIdVisitorSkeleton
<'_
, 'tcx
, V
>
125 V
: DefIdVisitor
<'tcx
> + ?Sized
,
127 fn visit_ty(&mut self, ty
: Ty
<'tcx
>) -> bool
{
128 let tcx
= self.def_id_visitor
.tcx();
129 // InternalSubsts are not visited here because they are visited below in `super_visit_with`.
131 ty
::Adt(&ty
::AdtDef { did: def_id, .. }
, ..)
132 | ty
::Foreign(def_id
)
133 | ty
::FnDef(def_id
, ..)
134 | ty
::Closure(def_id
, ..)
135 | ty
::Generator(def_id
, ..) => {
136 if self.def_id_visitor
.visit_def_id(def_id
, "type", &ty
) {
139 if self.def_id_visitor
.shallow() {
142 // Default type visitor doesn't visit signatures of fn types.
143 // Something like `fn() -> Priv {my_func}` is considered a private type even if
144 // `my_func` is public, so we need to visit signatures.
145 if let ty
::FnDef(..) = ty
.kind() {
146 if tcx
.fn_sig(def_id
).visit_with(self) {
150 // Inherent static methods don't have self type in substs.
151 // Something like `fn() {my_method}` type of the method
152 // `impl Pub<Priv> { pub fn my_method() {} }` is considered a private type,
153 // so we need to visit the self type additionally.
154 if let Some(assoc_item
) = tcx
.opt_associated_item(def_id
) {
155 if let ty
::ImplContainer(impl_def_id
) = assoc_item
.container
{
156 if tcx
.type_of(impl_def_id
).visit_with(self) {
162 ty
::Projection(proj
) => {
163 if self.def_id_visitor
.skip_assoc_tys() {
164 // Visitors searching for minimal visibility/reachability want to
165 // conservatively approximate associated types like `<Type as Trait>::Alias`
166 // as visible/reachable even if both `Type` and `Trait` are private.
167 // Ideally, associated types should be substituted in the same way as
168 // free type aliases, but this isn't done yet.
171 // This will also visit substs if necessary, so we don't need to recurse.
172 return self.visit_trait(proj
.trait_ref(tcx
));
174 ty
::Dynamic(predicates
, ..) => {
175 // All traits in the list are considered the "primary" part of the type
176 // and are visited by shallow visitors.
177 for predicate
in predicates
.skip_binder() {
178 let trait_ref
= match predicate
{
179 ty
::ExistentialPredicate
::Trait(trait_ref
) => trait_ref
,
180 ty
::ExistentialPredicate
::Projection(proj
) => proj
.trait_ref(tcx
),
181 ty
::ExistentialPredicate
::AutoTrait(def_id
) => {
182 ty
::ExistentialTraitRef { def_id, substs: InternalSubsts::empty() }
185 let ty
::ExistentialTraitRef { def_id, substs: _ }
= trait_ref
;
186 if self.def_id_visitor
.visit_def_id(def_id
, "trait", &trait_ref
) {
191 ty
::Opaque(def_id
, ..) => {
192 // Skip repeated `Opaque`s to avoid infinite recursion.
193 if self.visited_opaque_tys
.insert(def_id
) {
194 // The intent is to treat `impl Trait1 + Trait2` identically to
195 // `dyn Trait1 + Trait2`. Therefore we ignore def-id of the opaque type itself
196 // (it either has no visibility, or its visibility is insignificant, like
197 // visibilities of type aliases) and recurse into predicates instead to go
198 // through the trait list (default type visitor doesn't visit those traits).
199 // All traits in the list are considered the "primary" part of the type
200 // and are visited by shallow visitors.
201 if self.visit_predicates(tcx
.predicates_of(def_id
)) {
206 // These types don't have their own def-ids (but may have subcomponents
207 // with def-ids that should be visited recursively).
223 | ty
::GeneratorWitness(..) => {}
224 ty
::Bound(..) | ty
::Placeholder(..) | ty
::Infer(..) => {
225 bug
!("unexpected type: {:?}", ty
)
229 !self.def_id_visitor
.shallow() && ty
.super_visit_with(self)
233 fn def_id_visibility
<'tcx
>(
236 ) -> (ty
::Visibility
, Span
, &'
static str) {
237 match def_id
.as_local().map(|def_id
| tcx
.hir().local_def_id_to_hir_id(def_id
)) {
239 let vis
= match tcx
.hir().get(hir_id
) {
240 Node
::Item(item
) => &item
.vis
,
241 Node
::ForeignItem(foreign_item
) => &foreign_item
.vis
,
242 Node
::MacroDef(macro_def
) => {
243 if tcx
.sess
.contains_name(¯o_def
.attrs
, sym
::macro_export
) {
244 return (ty
::Visibility
::Public
, macro_def
.span
, "public");
249 Node
::TraitItem(..) | Node
::Variant(..) => {
250 return def_id_visibility(tcx
, tcx
.hir().get_parent_did(hir_id
).to_def_id());
252 Node
::ImplItem(impl_item
) => {
253 match tcx
.hir().get(tcx
.hir().get_parent_item(hir_id
)) {
254 Node
::Item(item
) => match &item
.kind
{
255 hir
::ItemKind
::Impl { of_trait: None, .. }
=> &impl_item
.vis
,
256 hir
::ItemKind
::Impl { of_trait: Some(trait_ref), .. }
=> {
257 return def_id_visibility(tcx
, trait_ref
.path
.res
.def_id());
259 kind
=> bug
!("unexpected item kind: {:?}", kind
),
261 node
=> bug
!("unexpected node kind: {:?}", node
),
264 Node
::Ctor(vdata
) => {
265 let parent_hir_id
= tcx
.hir().get_parent_node(hir_id
);
266 match tcx
.hir().get(parent_hir_id
) {
267 Node
::Variant(..) => {
268 let parent_did
= tcx
.hir().local_def_id(parent_hir_id
);
269 let (mut ctor_vis
, mut span
, mut descr
) =
270 def_id_visibility(tcx
, parent_did
.to_def_id());
272 let adt_def
= tcx
.adt_def(tcx
.hir().get_parent_did(hir_id
).to_def_id());
273 let ctor_did
= tcx
.hir().local_def_id(vdata
.ctor_hir_id().unwrap());
274 let variant
= adt_def
.variant_with_ctor_id(ctor_did
.to_def_id());
276 if variant
.is_field_list_non_exhaustive()
277 && ctor_vis
== ty
::Visibility
::Public
280 ty
::Visibility
::Restricted(DefId
::local(CRATE_DEF_INDEX
));
281 let attrs
= tcx
.get_attrs(variant
.def_id
);
284 .find_by_name(&attrs
, sym
::non_exhaustive
)
287 descr
= "crate-visible";
290 return (ctor_vis
, span
, descr
);
293 let item
= match tcx
.hir().get(parent_hir_id
) {
294 Node
::Item(item
) => item
,
295 node
=> bug
!("unexpected node kind: {:?}", node
),
297 let (mut ctor_vis
, mut span
, mut descr
) = (
298 ty
::Visibility
::from_hir(&item
.vis
, parent_hir_id
, tcx
),
300 item
.vis
.node
.descr(),
302 for field
in vdata
.fields() {
303 let field_vis
= ty
::Visibility
::from_hir(&field
.vis
, hir_id
, tcx
);
304 if ctor_vis
.is_at_least(field_vis
, tcx
) {
305 ctor_vis
= field_vis
;
306 span
= field
.vis
.span
;
307 descr
= field
.vis
.node
.descr();
311 // If the structure is marked as non_exhaustive then lower the
312 // visibility to within the crate.
313 if ctor_vis
== ty
::Visibility
::Public
{
315 tcx
.adt_def(tcx
.hir().get_parent_did(hir_id
).to_def_id());
316 if adt_def
.non_enum_variant().is_field_list_non_exhaustive() {
318 ty
::Visibility
::Restricted(DefId
::local(CRATE_DEF_INDEX
));
321 .find_by_name(&item
.attrs
, sym
::non_exhaustive
)
324 descr
= "crate-visible";
328 return (ctor_vis
, span
, descr
);
330 node
=> bug
!("unexpected node kind: {:?}", node
),
333 Node
::Expr(expr
) => {
335 ty
::Visibility
::Restricted(tcx
.parent_module(expr
.hir_id
).to_def_id()),
340 node
=> bug
!("unexpected node kind: {:?}", node
),
342 (ty
::Visibility
::from_hir(vis
, hir_id
, tcx
), vis
.span
, vis
.node
.descr())
345 let vis
= tcx
.visibility(def_id
);
346 let descr
= if vis
== ty
::Visibility
::Public { "public" }
else { "private" }
;
347 (vis
, tcx
.def_span(def_id
), descr
)
352 fn min(vis1
: ty
::Visibility
, vis2
: ty
::Visibility
, tcx
: TyCtxt
<'_
>) -> ty
::Visibility
{
353 if vis1
.is_at_least(vis2
, tcx
) { vis2 }
else { vis1 }
356 ////////////////////////////////////////////////////////////////////////////////
357 /// Visitor used to determine if pub(restricted) is used anywhere in the crate.
359 /// This is done so that `private_in_public` warnings can be turned into hard errors
360 /// in crates that have been updated to use pub(restricted).
361 ////////////////////////////////////////////////////////////////////////////////
362 struct PubRestrictedVisitor
<'tcx
> {
364 has_pub_restricted
: bool
,
367 impl Visitor
<'tcx
> for PubRestrictedVisitor
<'tcx
> {
368 type Map
= Map
<'tcx
>;
370 fn nested_visit_map(&mut self) -> NestedVisitorMap
<Self::Map
> {
371 NestedVisitorMap
::All(self.tcx
.hir())
373 fn visit_vis(&mut self, vis
: &'tcx hir
::Visibility
<'tcx
>) {
374 self.has_pub_restricted
= self.has_pub_restricted
|| vis
.node
.is_pub_restricted();
378 ////////////////////////////////////////////////////////////////////////////////
379 /// Visitor used to determine impl visibility and reachability.
380 ////////////////////////////////////////////////////////////////////////////////
382 struct FindMin
<'a
, 'tcx
, VL
: VisibilityLike
> {
384 access_levels
: &'a AccessLevels
,
388 impl<'a
, 'tcx
, VL
: VisibilityLike
> DefIdVisitor
<'tcx
> for FindMin
<'a
, 'tcx
, VL
> {
389 fn tcx(&self) -> TyCtxt
<'tcx
> {
392 fn shallow(&self) -> bool
{
395 fn skip_assoc_tys(&self) -> bool
{
398 fn visit_def_id(&mut self, def_id
: DefId
, _kind
: &str, _descr
: &dyn fmt
::Display
) -> bool
{
399 self.min
= VL
::new_min(self, def_id
);
404 trait VisibilityLike
: Sized
{
406 const SHALLOW
: bool
= false;
407 fn new_min(find
: &FindMin
<'_
, '_
, Self>, def_id
: DefId
) -> Self;
409 // Returns an over-approximation (`skip_assoc_tys` = true) of visibility due to
410 // associated types for which we can't determine visibility precisely.
411 fn of_impl(hir_id
: hir
::HirId
, tcx
: TyCtxt
<'_
>, access_levels
: &AccessLevels
) -> Self {
412 let mut find
= FindMin { tcx, access_levels, min: Self::MAX }
;
413 let def_id
= tcx
.hir().local_def_id(hir_id
);
414 find
.visit(tcx
.type_of(def_id
));
415 if let Some(trait_ref
) = tcx
.impl_trait_ref(def_id
) {
416 find
.visit_trait(trait_ref
);
421 impl VisibilityLike
for ty
::Visibility
{
422 const MAX
: Self = ty
::Visibility
::Public
;
423 fn new_min(find
: &FindMin
<'_
, '_
, Self>, def_id
: DefId
) -> Self {
424 min(def_id_visibility(find
.tcx
, def_id
).0, find
.min
, find
.tcx
)
427 impl VisibilityLike
for Option
<AccessLevel
> {
428 const MAX
: Self = Some(AccessLevel
::Public
);
429 // Type inference is very smart sometimes.
430 // It can make an impl reachable even some components of its type or trait are unreachable.
431 // E.g. methods of `impl ReachableTrait<UnreachableTy> for ReachableTy<UnreachableTy> { ... }`
432 // can be usable from other crates (#57264). So we skip substs when calculating reachability
433 // and consider an impl reachable if its "shallow" type and trait are reachable.
435 // The assumption we make here is that type-inference won't let you use an impl without knowing
436 // both "shallow" version of its self type and "shallow" version of its trait if it exists
437 // (which require reaching the `DefId`s in them).
438 const SHALLOW
: bool
= true;
439 fn new_min(find
: &FindMin
<'_
, '_
, Self>, def_id
: DefId
) -> Self {
441 if let Some(def_id
) = def_id
.as_local() {
442 let hir_id
= find
.tcx
.hir().local_def_id_to_hir_id(def_id
);
443 find
.access_levels
.map
.get(&hir_id
).cloned()
452 ////////////////////////////////////////////////////////////////////////////////
453 /// The embargo visitor, used to determine the exports of the AST.
454 ////////////////////////////////////////////////////////////////////////////////
456 struct EmbargoVisitor
<'tcx
> {
459 /// Accessibility levels for reachable nodes.
460 access_levels
: AccessLevels
,
461 /// A set of pairs corresponding to modules, where the first module is
462 /// reachable via a macro that's defined in the second module. This cannot
463 /// be represented as reachable because it can't handle the following case:
465 /// pub mod n { // Should be `Public`
466 /// pub(crate) mod p { // Should *not* be accessible
467 /// pub fn f() -> i32 { 12 } // Must be `Reachable`
473 macro_reachable
: FxHashSet
<(hir
::HirId
, DefId
)>,
474 /// Previous accessibility level; `None` means unreachable.
475 prev_level
: Option
<AccessLevel
>,
476 /// Has something changed in the level map?
480 struct ReachEverythingInTheInterfaceVisitor
<'a
, 'tcx
> {
481 access_level
: Option
<AccessLevel
>,
483 ev
: &'a
mut EmbargoVisitor
<'tcx
>,
486 impl EmbargoVisitor
<'tcx
> {
487 fn get(&self, id
: hir
::HirId
) -> Option
<AccessLevel
> {
488 self.access_levels
.map
.get(&id
).cloned()
491 /// Updates node level and returns the updated level.
492 fn update(&mut self, id
: hir
::HirId
, level
: Option
<AccessLevel
>) -> Option
<AccessLevel
> {
493 let old_level
= self.get(id
);
494 // Accessibility levels can only grow.
495 if level
> old_level
{
496 self.access_levels
.map
.insert(id
, level
.unwrap());
507 access_level
: Option
<AccessLevel
>,
508 ) -> ReachEverythingInTheInterfaceVisitor
<'_
, 'tcx
> {
509 ReachEverythingInTheInterfaceVisitor
{
510 access_level
: cmp
::min(access_level
, Some(AccessLevel
::Reachable
)),
511 item_def_id
: self.tcx
.hir().local_def_id(item_id
).to_def_id(),
516 /// Updates the item as being reachable through a macro defined in the given
517 /// module. Returns `true` if the level has changed.
518 fn update_macro_reachable(&mut self, reachable_mod
: hir
::HirId
, defining_mod
: DefId
) -> bool
{
519 if self.macro_reachable
.insert((reachable_mod
, defining_mod
)) {
520 self.update_macro_reachable_mod(reachable_mod
, defining_mod
);
527 fn update_macro_reachable_mod(&mut self, reachable_mod
: hir
::HirId
, defining_mod
: DefId
) {
528 let module_def_id
= self.tcx
.hir().local_def_id(reachable_mod
);
529 let module
= self.tcx
.hir().get_module(module_def_id
).0;
530 for item_id
in module
.item_ids
{
531 let hir_id
= item_id
.id
;
532 let item_def_id
= self.tcx
.hir().local_def_id(hir_id
);
533 let def_kind
= self.tcx
.def_kind(item_def_id
);
534 let item
= self.tcx
.hir().expect_item(hir_id
);
535 let vis
= ty
::Visibility
::from_hir(&item
.vis
, hir_id
, self.tcx
);
536 self.update_macro_reachable_def(hir_id
, def_kind
, vis
, defining_mod
);
538 if let Some(exports
) = self.tcx
.module_exports(module_def_id
) {
539 for export
in exports
{
540 if export
.vis
.is_accessible_from(defining_mod
, self.tcx
) {
541 if let Res
::Def(def_kind
, def_id
) = export
.res
{
542 let vis
= def_id_visibility(self.tcx
, def_id
).0;
543 if let Some(def_id
) = def_id
.as_local() {
544 let hir_id
= self.tcx
.hir().local_def_id_to_hir_id(def_id
);
545 self.update_macro_reachable_def(hir_id
, def_kind
, vis
, defining_mod
);
553 fn update_macro_reachable_def(
560 let level
= Some(AccessLevel
::Reachable
);
561 if let ty
::Visibility
::Public
= vis
{
562 self.update(hir_id
, level
);
565 // No type privacy, so can be directly marked as reachable.
569 | DefKind
::TraitAlias
570 | DefKind
::TyAlias
=> {
571 if vis
.is_accessible_from(module
, self.tcx
) {
572 self.update(hir_id
, level
);
576 // We can't use a module name as the final segment of a path, except
577 // in use statements. Since re-export checking doesn't consider
578 // hygiene these don't need to be marked reachable. The contents of
579 // the module, however may be reachable.
581 if vis
.is_accessible_from(module
, self.tcx
) {
582 self.update_macro_reachable(hir_id
, module
);
586 DefKind
::Struct
| DefKind
::Union
=> {
587 // While structs and unions have type privacy, their fields do
589 if let ty
::Visibility
::Public
= vis
{
590 let item
= self.tcx
.hir().expect_item(hir_id
);
591 if let hir
::ItemKind
::Struct(ref struct_def
, _
)
592 | hir
::ItemKind
::Union(ref struct_def
, _
) = item
.kind
594 for field
in struct_def
.fields() {
596 ty
::Visibility
::from_hir(&field
.vis
, field
.hir_id
, self.tcx
);
597 if field_vis
.is_accessible_from(module
, self.tcx
) {
598 self.reach(field
.hir_id
, level
).ty();
602 bug
!("item {:?} with DefKind {:?}", item
, def_kind
);
607 // These have type privacy, so are not reachable unless they're
608 // public, or are not namespaced at all.
611 | DefKind
::ConstParam
612 | DefKind
::Ctor(_
, _
)
621 | DefKind
::LifetimeParam
622 | DefKind
::ExternCrate
624 | DefKind
::ForeignMod
630 | DefKind
::Generator
=> (),
634 /// Given the path segments of a `ItemKind::Use`, then we need
635 /// to update the visibility of the intermediate use so that it isn't linted
636 /// by `unreachable_pub`.
638 /// This isn't trivial as `path.res` has the `DefId` of the eventual target
639 /// of the use statement not of the next intermediate use statement.
641 /// To do this, consider the last two segments of the path to our intermediate
642 /// use statement. We expect the penultimate segment to be a module and the
643 /// last segment to be the name of the item we are exporting. We can then
644 /// look at the items contained in the module for the use statement with that
645 /// name and update that item's visibility.
647 /// FIXME: This solution won't work with glob imports and doesn't respect
648 /// namespaces. See <https://github.com/rust-lang/rust/pull/57922#discussion_r251234202>.
649 fn update_visibility_of_intermediate_use_statements(
651 segments
: &[hir
::PathSegment
<'_
>],
653 if let [.., module
, segment
] = segments
{
654 if let Some(item
) = module
656 .and_then(|res
| res
.mod_def_id())
657 // If the module is `self`, i.e. the current crate,
658 // there will be no corresponding item.
659 .filter(|def_id
| def_id
.index
!= CRATE_DEF_INDEX
|| def_id
.krate
!= LOCAL_CRATE
)
661 def_id
.as_local().map(|def_id
| self.tcx
.hir().local_def_id_to_hir_id(def_id
))
663 .map(|module_hir_id
| self.tcx
.hir().expect_item(module_hir_id
))
665 if let hir
::ItemKind
::Mod(m
) = &item
.kind
{
666 for item_id
in m
.item_ids
{
667 let item
= self.tcx
.hir().expect_item(item_id
.id
);
668 let def_id
= self.tcx
.hir().local_def_id(item_id
.id
);
669 if !self.tcx
.hygienic_eq(segment
.ident
, item
.ident
, def_id
.to_def_id()) {
672 if let hir
::ItemKind
::Use(..) = item
.kind
{
673 self.update(item
.hir_id
, Some(AccessLevel
::Exported
));
682 impl Visitor
<'tcx
> for EmbargoVisitor
<'tcx
> {
683 type Map
= Map
<'tcx
>;
685 /// We want to visit items in the context of their containing
686 /// module and so forth, so supply a crate for doing a deep walk.
687 fn nested_visit_map(&mut self) -> NestedVisitorMap
<Self::Map
> {
688 NestedVisitorMap
::All(self.tcx
.hir())
691 fn visit_item(&mut self, item
: &'tcx hir
::Item
<'tcx
>) {
692 let inherited_item_level
= match item
.kind
{
693 hir
::ItemKind
::Impl { .. }
=> {
694 Option
::<AccessLevel
>::of_impl(item
.hir_id
, self.tcx
, &self.access_levels
)
696 // Foreign modules inherit level from parents.
697 hir
::ItemKind
::ForeignMod(..) => self.prev_level
,
698 // Other `pub` items inherit levels from parents.
699 hir
::ItemKind
::Const(..)
700 | hir
::ItemKind
::Enum(..)
701 | hir
::ItemKind
::ExternCrate(..)
702 | hir
::ItemKind
::GlobalAsm(..)
703 | hir
::ItemKind
::Fn(..)
704 | hir
::ItemKind
::Mod(..)
705 | hir
::ItemKind
::Static(..)
706 | hir
::ItemKind
::Struct(..)
707 | hir
::ItemKind
::Trait(..)
708 | hir
::ItemKind
::TraitAlias(..)
709 | hir
::ItemKind
::OpaqueTy(..)
710 | hir
::ItemKind
::TyAlias(..)
711 | hir
::ItemKind
::Union(..)
712 | hir
::ItemKind
::Use(..) => {
713 if item
.vis
.node
.is_pub() {
721 // Update level of the item itself.
722 let item_level
= self.update(item
.hir_id
, inherited_item_level
);
724 // Update levels of nested things.
726 hir
::ItemKind
::Enum(ref def
, _
) => {
727 for variant
in def
.variants
{
728 let variant_level
= self.update(variant
.id
, item_level
);
729 if let Some(ctor_hir_id
) = variant
.data
.ctor_hir_id() {
730 self.update(ctor_hir_id
, item_level
);
732 for field
in variant
.data
.fields() {
733 self.update(field
.hir_id
, variant_level
);
737 hir
::ItemKind
::Impl { ref of_trait, items, .. }
=> {
738 for impl_item_ref
in items
{
739 if of_trait
.is_some() || impl_item_ref
.vis
.node
.is_pub() {
740 self.update(impl_item_ref
.id
.hir_id
, item_level
);
744 hir
::ItemKind
::Trait(.., trait_item_refs
) => {
745 for trait_item_ref
in trait_item_refs
{
746 self.update(trait_item_ref
.id
.hir_id
, item_level
);
749 hir
::ItemKind
::Struct(ref def
, _
) | hir
::ItemKind
::Union(ref def
, _
) => {
750 if let Some(ctor_hir_id
) = def
.ctor_hir_id() {
751 self.update(ctor_hir_id
, item_level
);
753 for field
in def
.fields() {
754 if field
.vis
.node
.is_pub() {
755 self.update(field
.hir_id
, item_level
);
759 hir
::ItemKind
::ForeignMod(ref foreign_mod
) => {
760 for foreign_item
in foreign_mod
.items
{
761 if foreign_item
.vis
.node
.is_pub() {
762 self.update(foreign_item
.hir_id
, item_level
);
766 hir
::ItemKind
::OpaqueTy(..)
767 | hir
::ItemKind
::Use(..)
768 | hir
::ItemKind
::Static(..)
769 | hir
::ItemKind
::Const(..)
770 | hir
::ItemKind
::GlobalAsm(..)
771 | hir
::ItemKind
::TyAlias(..)
772 | hir
::ItemKind
::Mod(..)
773 | hir
::ItemKind
::TraitAlias(..)
774 | hir
::ItemKind
::Fn(..)
775 | hir
::ItemKind
::ExternCrate(..) => {}
778 // Mark all items in interfaces of reachable items as reachable.
780 // The interface is empty.
781 hir
::ItemKind
::ExternCrate(..) => {}
782 // All nested items are checked by `visit_item`.
783 hir
::ItemKind
::Mod(..) => {}
784 // Re-exports are handled in `visit_mod`. However, in order to avoid looping over
785 // all of the items of a mod in `visit_mod` looking for use statements, we handle
786 // making sure that intermediate use statements have their visibilities updated here.
787 hir
::ItemKind
::Use(ref path
, _
) => {
788 if item_level
.is_some() {
789 self.update_visibility_of_intermediate_use_statements(path
.segments
.as_ref());
792 // The interface is empty.
793 hir
::ItemKind
::GlobalAsm(..) => {}
794 hir
::ItemKind
::OpaqueTy(..) => {
795 // HACK(jynelson): trying to infer the type of `impl trait` breaks `async-std` (and `pub async fn` in general)
796 // Since rustdoc never need to do codegen and doesn't care about link-time reachability,
797 // mark this as unreachable.
798 // See https://github.com/rust-lang/rust/issues/75100
799 if !self.tcx
.sess
.opts
.actually_rustdoc
{
800 // FIXME: This is some serious pessimization intended to workaround deficiencies
801 // in the reachability pass (`middle/reachable.rs`). Types are marked as link-time
802 // reachable if they are returned via `impl Trait`, even from private functions.
804 cmp
::max(item_level
, Some(AccessLevel
::ReachableFromImplTrait
));
805 self.reach(item
.hir_id
, exist_level
).generics().predicates().ty();
809 hir
::ItemKind
::Const(..)
810 | hir
::ItemKind
::Static(..)
811 | hir
::ItemKind
::Fn(..)
812 | hir
::ItemKind
::TyAlias(..) => {
813 if item_level
.is_some() {
814 self.reach(item
.hir_id
, item_level
).generics().predicates().ty();
817 hir
::ItemKind
::Trait(.., trait_item_refs
) => {
818 if item_level
.is_some() {
819 self.reach(item
.hir_id
, item_level
).generics().predicates();
821 for trait_item_ref
in trait_item_refs
{
822 let mut reach
= self.reach(trait_item_ref
.id
.hir_id
, item_level
);
823 reach
.generics().predicates();
825 if trait_item_ref
.kind
== AssocItemKind
::Type
826 && !trait_item_ref
.defaultness
.has_value()
835 hir
::ItemKind
::TraitAlias(..) => {
836 if item_level
.is_some() {
837 self.reach(item
.hir_id
, item_level
).generics().predicates();
840 // Visit everything except for private impl items.
841 hir
::ItemKind
::Impl { items, .. }
=> {
842 if item_level
.is_some() {
843 self.reach(item
.hir_id
, item_level
).generics().predicates().ty().trait_ref();
845 for impl_item_ref
in items
{
846 let impl_item_level
= self.get(impl_item_ref
.id
.hir_id
);
847 if impl_item_level
.is_some() {
848 self.reach(impl_item_ref
.id
.hir_id
, impl_item_level
)
857 // Visit everything, but enum variants have their own levels.
858 hir
::ItemKind
::Enum(ref def
, _
) => {
859 if item_level
.is_some() {
860 self.reach(item
.hir_id
, item_level
).generics().predicates();
862 for variant
in def
.variants
{
863 let variant_level
= self.get(variant
.id
);
864 if variant_level
.is_some() {
865 for field
in variant
.data
.fields() {
866 self.reach(field
.hir_id
, variant_level
).ty();
868 // Corner case: if the variant is reachable, but its
869 // enum is not, make the enum reachable as well.
870 self.update(item
.hir_id
, variant_level
);
874 // Visit everything, but foreign items have their own levels.
875 hir
::ItemKind
::ForeignMod(ref foreign_mod
) => {
876 for foreign_item
in foreign_mod
.items
{
877 let foreign_item_level
= self.get(foreign_item
.hir_id
);
878 if foreign_item_level
.is_some() {
879 self.reach(foreign_item
.hir_id
, foreign_item_level
)
886 // Visit everything except for private fields.
887 hir
::ItemKind
::Struct(ref struct_def
, _
) | hir
::ItemKind
::Union(ref struct_def
, _
) => {
888 if item_level
.is_some() {
889 self.reach(item
.hir_id
, item_level
).generics().predicates();
890 for field
in struct_def
.fields() {
891 let field_level
= self.get(field
.hir_id
);
892 if field_level
.is_some() {
893 self.reach(field
.hir_id
, field_level
).ty();
900 let orig_level
= mem
::replace(&mut self.prev_level
, item_level
);
901 intravisit
::walk_item(self, item
);
902 self.prev_level
= orig_level
;
905 fn visit_block(&mut self, b
: &'tcx hir
::Block
<'tcx
>) {
906 // Blocks can have public items, for example impls, but they always
907 // start as completely private regardless of publicity of a function,
908 // constant, type, field, etc., in which this block resides.
909 let orig_level
= mem
::replace(&mut self.prev_level
, None
);
910 intravisit
::walk_block(self, b
);
911 self.prev_level
= orig_level
;
914 fn visit_mod(&mut self, m
: &'tcx hir
::Mod
<'tcx
>, _sp
: Span
, id
: hir
::HirId
) {
915 // This code is here instead of in visit_item so that the
916 // crate module gets processed as well.
917 if self.prev_level
.is_some() {
918 let def_id
= self.tcx
.hir().local_def_id(id
);
919 if let Some(exports
) = self.tcx
.module_exports(def_id
) {
920 for export
in exports
.iter() {
921 if export
.vis
== ty
::Visibility
::Public
{
922 if let Some(def_id
) = export
.res
.opt_def_id() {
923 if let Some(def_id
) = def_id
.as_local() {
924 let hir_id
= self.tcx
.hir().local_def_id_to_hir_id(def_id
);
925 self.update(hir_id
, Some(AccessLevel
::Exported
));
933 intravisit
::walk_mod(self, m
, id
);
936 fn visit_macro_def(&mut self, md
: &'tcx hir
::MacroDef
<'tcx
>) {
937 if attr
::find_transparency(&self.tcx
.sess
, &md
.attrs
, md
.ast
.macro_rules
).0
938 != Transparency
::Opaque
940 self.update(md
.hir_id
, Some(AccessLevel
::Public
));
944 let macro_module_def_id
=
945 ty
::DefIdTree
::parent(self.tcx
, self.tcx
.hir().local_def_id(md
.hir_id
).to_def_id())
947 // FIXME(#71104) Should really be using just `as_local_hir_id` but
948 // some `DefId` do not seem to have a corresponding HirId.
949 let hir_id
= macro_module_def_id
951 .and_then(|def_id
| self.tcx
.hir().opt_local_def_id_to_hir_id(def_id
));
952 let mut module_id
= match hir_id
{
953 Some(module_id
) if self.tcx
.hir().is_hir_id_module(module_id
) => module_id
,
954 // `module_id` doesn't correspond to a `mod`, return early (#63164, #65252).
957 let level
= if md
.vis
.node
.is_pub() { self.get(module_id) }
else { None }
;
958 let new_level
= self.update(md
.hir_id
, level
);
959 if new_level
.is_none() {
964 let changed_reachability
= self.update_macro_reachable(module_id
, macro_module_def_id
);
965 if changed_reachability
|| module_id
== hir
::CRATE_HIR_ID
{
968 module_id
= self.tcx
.hir().get_parent_node(module_id
);
973 impl ReachEverythingInTheInterfaceVisitor
<'_
, 'tcx
> {
974 fn generics(&mut self) -> &mut Self {
975 for param
in &self.ev
.tcx
.generics_of(self.item_def_id
).params
{
977 GenericParamDefKind
::Lifetime
=> {}
978 GenericParamDefKind
::Type { has_default, .. }
=> {
980 self.visit(self.ev
.tcx
.type_of(param
.def_id
));
983 GenericParamDefKind
::Const
=> {
984 self.visit(self.ev
.tcx
.type_of(param
.def_id
));
991 fn predicates(&mut self) -> &mut Self {
992 self.visit_predicates(self.ev
.tcx
.predicates_of(self.item_def_id
));
996 fn ty(&mut self) -> &mut Self {
997 self.visit(self.ev
.tcx
.type_of(self.item_def_id
));
1001 fn trait_ref(&mut self) -> &mut Self {
1002 if let Some(trait_ref
) = self.ev
.tcx
.impl_trait_ref(self.item_def_id
) {
1003 self.visit_trait(trait_ref
);
1009 impl DefIdVisitor
<'tcx
> for ReachEverythingInTheInterfaceVisitor
<'_
, 'tcx
> {
1010 fn tcx(&self) -> TyCtxt
<'tcx
> {
1013 fn visit_def_id(&mut self, def_id
: DefId
, _kind
: &str, _descr
: &dyn fmt
::Display
) -> bool
{
1014 if let Some(def_id
) = def_id
.as_local() {
1015 let hir_id
= self.ev
.tcx
.hir().local_def_id_to_hir_id(def_id
);
1016 if let ((ty
::Visibility
::Public
, ..), _
)
1017 | (_
, Some(AccessLevel
::ReachableFromImplTrait
)) =
1018 (def_id_visibility(self.tcx(), def_id
.to_def_id()), self.access_level
)
1020 self.ev
.update(hir_id
, self.access_level
);
1027 //////////////////////////////////////////////////////////////////////////////////////
1028 /// Name privacy visitor, checks privacy and reports violations.
1029 /// Most of name privacy checks are performed during the main resolution phase,
1030 /// or later in type checking when field accesses and associated items are resolved.
1031 /// This pass performs remaining checks for fields in struct expressions and patterns.
1032 //////////////////////////////////////////////////////////////////////////////////////
1034 struct NamePrivacyVisitor
<'tcx
> {
1036 maybe_typeck_results
: Option
<&'tcx ty
::TypeckResults
<'tcx
>>,
1037 current_item
: Option
<hir
::HirId
>,
1040 impl<'tcx
> NamePrivacyVisitor
<'tcx
> {
1041 /// Gets the type-checking results for the current body.
1042 /// As this will ICE if called outside bodies, only call when working with
1043 /// `Expr` or `Pat` nodes (they are guaranteed to be found only in bodies).
1045 fn typeck_results(&self) -> &'tcx ty
::TypeckResults
<'tcx
> {
1046 self.maybe_typeck_results
1047 .expect("`NamePrivacyVisitor::typeck_results` called outside of body")
1050 // Checks that a field in a struct constructor (expression or pattern) is accessible.
1053 use_ctxt
: Span
, // syntax context of the field name at the use site
1054 span
: Span
, // span of the field pattern, e.g., `x: 0`
1055 def
: &'tcx ty
::AdtDef
, // definition of the struct or enum
1056 field
: &'tcx ty
::FieldDef
,
1057 in_update_syntax
: bool
,
1059 // definition of the field
1060 let ident
= Ident
::new(kw
::Invalid
, use_ctxt
);
1061 let current_hir
= self.current_item
.unwrap();
1062 let def_id
= self.tcx
.adjust_ident_and_get_scope(ident
, def
.did
, current_hir
).1;
1063 if !def
.is_enum() && !field
.vis
.is_accessible_from(def_id
, self.tcx
) {
1064 let label
= if in_update_syntax
{
1065 format
!("field `{}` is private", field
.ident
)
1067 "private field".to_string()
1074 "field `{}` of {} `{}` is private",
1076 def
.variant_descr(),
1077 self.tcx
.def_path_str(def
.did
)
1079 .span_label(span
, label
)
1085 impl<'tcx
> Visitor
<'tcx
> for NamePrivacyVisitor
<'tcx
> {
1086 type Map
= Map
<'tcx
>;
1088 /// We want to visit items in the context of their containing
1089 /// module and so forth, so supply a crate for doing a deep walk.
1090 fn nested_visit_map(&mut self) -> NestedVisitorMap
<Self::Map
> {
1091 NestedVisitorMap
::All(self.tcx
.hir())
1094 fn visit_mod(&mut self, _m
: &'tcx hir
::Mod
<'tcx
>, _s
: Span
, _n
: hir
::HirId
) {
1095 // Don't visit nested modules, since we run a separate visitor walk
1096 // for each module in `privacy_access_levels`
1099 fn visit_nested_body(&mut self, body
: hir
::BodyId
) {
1100 let old_maybe_typeck_results
=
1101 self.maybe_typeck_results
.replace(self.tcx
.typeck_body(body
));
1102 let body
= self.tcx
.hir().body(body
);
1103 self.visit_body(body
);
1104 self.maybe_typeck_results
= old_maybe_typeck_results
;
1107 fn visit_item(&mut self, item
: &'tcx hir
::Item
<'tcx
>) {
1108 let orig_current_item
= self.current_item
.replace(item
.hir_id
);
1109 intravisit
::walk_item(self, item
);
1110 self.current_item
= orig_current_item
;
1113 fn visit_expr(&mut self, expr
: &'tcx hir
::Expr
<'tcx
>) {
1114 if let hir
::ExprKind
::Struct(ref qpath
, fields
, ref base
) = expr
.kind
{
1115 let res
= self.typeck_results().qpath_res(qpath
, expr
.hir_id
);
1116 let adt
= self.typeck_results().expr_ty(expr
).ty_adt_def().unwrap();
1117 let variant
= adt
.variant_of_res(res
);
1118 if let Some(ref base
) = *base
{
1119 // If the expression uses FRU we need to make sure all the unmentioned fields
1120 // are checked for privacy (RFC 736). Rather than computing the set of
1121 // unmentioned fields, just check them all.
1122 for (vf_index
, variant_field
) in variant
.fields
.iter().enumerate() {
1123 let field
= fields
.iter().find(|f
| {
1124 self.tcx
.field_index(f
.hir_id
, self.typeck_results()) == vf_index
1126 let (use_ctxt
, span
) = match field
{
1127 Some(field
) => (field
.ident
.span
, field
.span
),
1128 None
=> (base
.span
, base
.span
),
1130 self.check_field(use_ctxt
, span
, adt
, variant_field
, true);
1133 for field
in fields
{
1134 let use_ctxt
= field
.ident
.span
;
1135 let index
= self.tcx
.field_index(field
.hir_id
, self.typeck_results());
1136 self.check_field(use_ctxt
, field
.span
, adt
, &variant
.fields
[index
], false);
1141 intravisit
::walk_expr(self, expr
);
1144 fn visit_pat(&mut self, pat
: &'tcx hir
::Pat
<'tcx
>) {
1145 if let PatKind
::Struct(ref qpath
, fields
, _
) = pat
.kind
{
1146 let res
= self.typeck_results().qpath_res(qpath
, pat
.hir_id
);
1147 let adt
= self.typeck_results().pat_ty(pat
).ty_adt_def().unwrap();
1148 let variant
= adt
.variant_of_res(res
);
1149 for field
in fields
{
1150 let use_ctxt
= field
.ident
.span
;
1151 let index
= self.tcx
.field_index(field
.hir_id
, self.typeck_results());
1152 self.check_field(use_ctxt
, field
.span
, adt
, &variant
.fields
[index
], false);
1156 intravisit
::walk_pat(self, pat
);
1160 ////////////////////////////////////////////////////////////////////////////////////////////
1161 /// Type privacy visitor, checks types for privacy and reports violations.
1162 /// Both explicitly written types and inferred types of expressions and patters are checked.
1163 /// Checks are performed on "semantic" types regardless of names and their hygiene.
1164 ////////////////////////////////////////////////////////////////////////////////////////////
1166 struct TypePrivacyVisitor
<'tcx
> {
1168 maybe_typeck_results
: Option
<&'tcx ty
::TypeckResults
<'tcx
>>,
1169 current_item
: LocalDefId
,
1173 impl<'tcx
> TypePrivacyVisitor
<'tcx
> {
1174 /// Gets the type-checking results for the current body.
1175 /// As this will ICE if called outside bodies, only call when working with
1176 /// `Expr` or `Pat` nodes (they are guaranteed to be found only in bodies).
1178 fn typeck_results(&self) -> &'tcx ty
::TypeckResults
<'tcx
> {
1179 self.maybe_typeck_results
1180 .expect("`TypePrivacyVisitor::typeck_results` called outside of body")
1183 fn item_is_accessible(&self, did
: DefId
) -> bool
{
1184 def_id_visibility(self.tcx
, did
)
1186 .is_accessible_from(self.current_item
.to_def_id(), self.tcx
)
1189 // Take node-id of an expression or pattern and check its type for privacy.
1190 fn check_expr_pat_type(&mut self, id
: hir
::HirId
, span
: Span
) -> bool
{
1192 let typeck_results
= self.typeck_results();
1193 if self.visit(typeck_results
.node_type(id
)) || self.visit(typeck_results
.node_substs(id
)) {
1196 if let Some(adjustments
) = typeck_results
.adjustments().get(id
) {
1197 for adjustment
in adjustments
{
1198 if self.visit(adjustment
.target
) {
1206 fn check_def_id(&mut self, def_id
: DefId
, kind
: &str, descr
: &dyn fmt
::Display
) -> bool
{
1207 let is_error
= !self.item_is_accessible(def_id
);
1211 .struct_span_err(self.span
, &format
!("{} `{}` is private", kind
, descr
))
1212 .span_label(self.span
, &format
!("private {}", kind
))
1219 impl<'tcx
> Visitor
<'tcx
> for TypePrivacyVisitor
<'tcx
> {
1220 type Map
= Map
<'tcx
>;
1222 /// We want to visit items in the context of their containing
1223 /// module and so forth, so supply a crate for doing a deep walk.
1224 fn nested_visit_map(&mut self) -> NestedVisitorMap
<Self::Map
> {
1225 NestedVisitorMap
::All(self.tcx
.hir())
1228 fn visit_mod(&mut self, _m
: &'tcx hir
::Mod
<'tcx
>, _s
: Span
, _n
: hir
::HirId
) {
1229 // Don't visit nested modules, since we run a separate visitor walk
1230 // for each module in `privacy_access_levels`
1233 fn visit_nested_body(&mut self, body
: hir
::BodyId
) {
1234 let old_maybe_typeck_results
=
1235 self.maybe_typeck_results
.replace(self.tcx
.typeck_body(body
));
1236 let body
= self.tcx
.hir().body(body
);
1237 self.visit_body(body
);
1238 self.maybe_typeck_results
= old_maybe_typeck_results
;
1241 fn visit_ty(&mut self, hir_ty
: &'tcx hir
::Ty
<'tcx
>) {
1242 self.span
= hir_ty
.span
;
1243 if let Some(typeck_results
) = self.maybe_typeck_results
{
1245 if self.visit(typeck_results
.node_type(hir_ty
.hir_id
)) {
1249 // Types in signatures.
1250 // FIXME: This is very ineffective. Ideally each HIR type should be converted
1251 // into a semantic type only once and the result should be cached somehow.
1252 if self.visit(rustc_typeck
::hir_ty_to_ty(self.tcx
, hir_ty
)) {
1257 intravisit
::walk_ty(self, hir_ty
);
1260 fn visit_trait_ref(&mut self, trait_ref
: &'tcx hir
::TraitRef
<'tcx
>) {
1261 self.span
= trait_ref
.path
.span
;
1262 if self.maybe_typeck_results
.is_none() {
1263 // Avoid calling `hir_trait_to_predicates` in bodies, it will ICE.
1264 // The traits' privacy in bodies is already checked as a part of trait object types.
1265 let bounds
= rustc_typeck
::hir_trait_to_predicates(
1268 // NOTE: This isn't really right, but the actual type doesn't matter here. It's
1269 // just required by `ty::TraitRef`.
1270 self.tcx
.types
.never
,
1273 for (trait_predicate
, _
, _
) in bounds
.trait_bounds
{
1274 if self.visit_trait(trait_predicate
.skip_binder()) {
1279 for (poly_predicate
, _
) in bounds
.projection_bounds
{
1281 if self.visit(poly_predicate
.skip_binder().ty
)
1282 || self.visit_trait(poly_predicate
.skip_binder().projection_ty
.trait_ref(tcx
))
1289 intravisit
::walk_trait_ref(self, trait_ref
);
1292 // Check types of expressions
1293 fn visit_expr(&mut self, expr
: &'tcx hir
::Expr
<'tcx
>) {
1294 if self.check_expr_pat_type(expr
.hir_id
, expr
.span
) {
1295 // Do not check nested expressions if the error already happened.
1299 hir
::ExprKind
::Assign(_
, ref rhs
, _
) | hir
::ExprKind
::Match(ref rhs
, ..) => {
1300 // Do not report duplicate errors for `x = y` and `match x { ... }`.
1301 if self.check_expr_pat_type(rhs
.hir_id
, rhs
.span
) {
1305 hir
::ExprKind
::MethodCall(_
, span
, _
, _
) => {
1306 // Method calls have to be checked specially.
1308 if let Some(def_id
) = self.typeck_results().type_dependent_def_id(expr
.hir_id
) {
1309 if self.visit(self.tcx
.type_of(def_id
)) {
1315 .delay_span_bug(expr
.span
, "no type-dependent def for method call");
1321 intravisit
::walk_expr(self, expr
);
1324 // Prohibit access to associated items with insufficient nominal visibility.
1326 // Additionally, until better reachability analysis for macros 2.0 is available,
1327 // we prohibit access to private statics from other crates, this allows to give
1328 // more code internal visibility at link time. (Access to private functions
1329 // is already prohibited by type privacy for function types.)
1330 fn visit_qpath(&mut self, qpath
: &'tcx hir
::QPath
<'tcx
>, id
: hir
::HirId
, span
: Span
) {
1331 let def
= match qpath
{
1332 hir
::QPath
::Resolved(_
, path
) => match path
.res
{
1333 Res
::Def(kind
, def_id
) => Some((kind
, def_id
)),
1336 hir
::QPath
::TypeRelative(..) | hir
::QPath
::LangItem(..) => self
1337 .maybe_typeck_results
1338 .and_then(|typeck_results
| typeck_results
.type_dependent_def(id
)),
1340 let def
= def
.filter(|(kind
, _
)| match kind
{
1341 DefKind
::AssocFn
| DefKind
::AssocConst
| DefKind
::AssocTy
| DefKind
::Static
=> true,
1344 if let Some((kind
, def_id
)) = def
{
1345 let is_local_static
=
1346 if let DefKind
::Static
= kind { def_id.is_local() }
else { false }
;
1347 if !self.item_is_accessible(def_id
) && !is_local_static
{
1348 let sess
= self.tcx
.sess
;
1349 let sm
= sess
.source_map();
1350 let name
= match qpath
{
1351 hir
::QPath
::Resolved(..) | hir
::QPath
::LangItem(..) => {
1352 sm
.span_to_snippet(qpath
.span()).ok()
1354 hir
::QPath
::TypeRelative(_
, segment
) => Some(segment
.ident
.to_string()),
1356 let kind
= kind
.descr(def_id
);
1357 let msg
= match name
{
1358 Some(name
) => format
!("{} `{}` is private", kind
, name
),
1359 None
=> format
!("{} is private", kind
),
1361 sess
.struct_span_err(span
, &msg
)
1362 .span_label(span
, &format
!("private {}", kind
))
1368 intravisit
::walk_qpath(self, qpath
, id
, span
);
1371 // Check types of patterns.
1372 fn visit_pat(&mut self, pattern
: &'tcx hir
::Pat
<'tcx
>) {
1373 if self.check_expr_pat_type(pattern
.hir_id
, pattern
.span
) {
1374 // Do not check nested patterns if the error already happened.
1378 intravisit
::walk_pat(self, pattern
);
1381 fn visit_local(&mut self, local
: &'tcx hir
::Local
<'tcx
>) {
1382 if let Some(ref init
) = local
.init
{
1383 if self.check_expr_pat_type(init
.hir_id
, init
.span
) {
1384 // Do not report duplicate errors for `let x = y`.
1389 intravisit
::walk_local(self, local
);
1392 // Check types in item interfaces.
1393 fn visit_item(&mut self, item
: &'tcx hir
::Item
<'tcx
>) {
1394 let orig_current_item
=
1395 mem
::replace(&mut self.current_item
, self.tcx
.hir().local_def_id(item
.hir_id
));
1396 let old_maybe_typeck_results
= self.maybe_typeck_results
.take();
1397 intravisit
::walk_item(self, item
);
1398 self.maybe_typeck_results
= old_maybe_typeck_results
;
1399 self.current_item
= orig_current_item
;
1403 impl DefIdVisitor
<'tcx
> for TypePrivacyVisitor
<'tcx
> {
1404 fn tcx(&self) -> TyCtxt
<'tcx
> {
1407 fn visit_def_id(&mut self, def_id
: DefId
, kind
: &str, descr
: &dyn fmt
::Display
) -> bool
{
1408 self.check_def_id(def_id
, kind
, descr
)
1412 ///////////////////////////////////////////////////////////////////////////////
1413 /// Obsolete visitors for checking for private items in public interfaces.
1414 /// These visitors are supposed to be kept in frozen state and produce an
1415 /// "old error node set". For backward compatibility the new visitor reports
1416 /// warnings instead of hard errors when the erroneous node is not in this old set.
1417 ///////////////////////////////////////////////////////////////////////////////
1419 struct ObsoleteVisiblePrivateTypesVisitor
<'a
, 'tcx
> {
1421 access_levels
: &'a AccessLevels
,
1423 // Set of errors produced by this obsolete visitor.
1424 old_error_set
: HirIdSet
,
1427 struct ObsoleteCheckTypeForPrivatenessVisitor
<'a
, 'b
, 'tcx
> {
1428 inner
: &'a ObsoleteVisiblePrivateTypesVisitor
<'b
, 'tcx
>,
1429 /// Whether the type refers to private types.
1430 contains_private
: bool
,
1431 /// Whether we've recurred at all (i.e., if we're pointing at the
1432 /// first type on which `visit_ty` was called).
1433 at_outer_type
: bool
,
1434 /// Whether that first type is a public path.
1435 outer_type_is_public_path
: bool
,
1438 impl<'a
, 'tcx
> ObsoleteVisiblePrivateTypesVisitor
<'a
, 'tcx
> {
1439 fn path_is_private_type(&self, path
: &hir
::Path
<'_
>) -> bool
{
1440 let did
= match path
.res
{
1441 Res
::PrimTy(..) | Res
::SelfTy(..) | Res
::Err
=> return false,
1442 res
=> res
.def_id(),
1445 // A path can only be private if:
1446 // it's in this crate...
1447 if let Some(did
) = did
.as_local() {
1448 // .. and it corresponds to a private type in the AST (this returns
1449 // `None` for type parameters).
1450 match self.tcx
.hir().find(self.tcx
.hir().local_def_id_to_hir_id(did
)) {
1451 Some(Node
::Item(ref item
)) => !item
.vis
.node
.is_pub(),
1452 Some(_
) | None
=> false,
1459 fn trait_is_public(&self, trait_id
: hir
::HirId
) -> bool
{
1460 // FIXME: this would preferably be using `exported_items`, but all
1461 // traits are exported currently (see `EmbargoVisitor.exported_trait`).
1462 self.access_levels
.is_public(trait_id
)
1465 fn check_generic_bound(&mut self, bound
: &hir
::GenericBound
<'_
>) {
1466 if let hir
::GenericBound
::Trait(ref trait_ref
, _
) = *bound
{
1467 if self.path_is_private_type(&trait_ref
.trait_ref
.path
) {
1468 self.old_error_set
.insert(trait_ref
.trait_ref
.hir_ref_id
);
1473 fn item_is_public(&self, id
: &hir
::HirId
, vis
: &hir
::Visibility
<'_
>) -> bool
{
1474 self.access_levels
.is_reachable(*id
) || vis
.node
.is_pub()
1478 impl<'a
, 'b
, 'tcx
, 'v
> Visitor
<'v
> for ObsoleteCheckTypeForPrivatenessVisitor
<'a
, 'b
, 'tcx
> {
1479 type Map
= intravisit
::ErasedMap
<'v
>;
1481 fn nested_visit_map(&mut self) -> NestedVisitorMap
<Self::Map
> {
1482 NestedVisitorMap
::None
1485 fn visit_ty(&mut self, ty
: &hir
::Ty
<'_
>) {
1486 if let hir
::TyKind
::Path(hir
::QPath
::Resolved(_
, ref path
)) = ty
.kind
{
1487 if self.inner
.path_is_private_type(path
) {
1488 self.contains_private
= true;
1489 // Found what we're looking for, so let's stop working.
1493 if let hir
::TyKind
::Path(_
) = ty
.kind
{
1494 if self.at_outer_type
{
1495 self.outer_type_is_public_path
= true;
1498 self.at_outer_type
= false;
1499 intravisit
::walk_ty(self, ty
)
1502 // Don't want to recurse into `[, .. expr]`.
1503 fn visit_expr(&mut self, _
: &hir
::Expr
<'_
>) {}
1506 impl<'a
, 'tcx
> Visitor
<'tcx
> for ObsoleteVisiblePrivateTypesVisitor
<'a
, 'tcx
> {
1507 type Map
= Map
<'tcx
>;
1509 /// We want to visit items in the context of their containing
1510 /// module and so forth, so supply a crate for doing a deep walk.
1511 fn nested_visit_map(&mut self) -> NestedVisitorMap
<Self::Map
> {
1512 NestedVisitorMap
::All(self.tcx
.hir())
1515 fn visit_item(&mut self, item
: &'tcx hir
::Item
<'tcx
>) {
1517 // Contents of a private mod can be re-exported, so we need
1518 // to check internals.
1519 hir
::ItemKind
::Mod(_
) => {}
1521 // An `extern {}` doesn't introduce a new privacy
1522 // namespace (the contents have their own privacies).
1523 hir
::ItemKind
::ForeignMod(_
) => {}
1525 hir
::ItemKind
::Trait(.., ref bounds
, _
) => {
1526 if !self.trait_is_public(item
.hir_id
) {
1530 for bound
in bounds
.iter() {
1531 self.check_generic_bound(bound
)
1535 // Impls need some special handling to try to offer useful
1536 // error messages without (too many) false positives
1537 // (i.e., we could just return here to not check them at
1538 // all, or some worse estimation of whether an impl is
1539 // publicly visible).
1540 hir
::ItemKind
::Impl { generics: ref g, ref of_trait, ref self_ty, items, .. }
=> {
1541 // `impl [... for] Private` is never visible.
1542 let self_contains_private
;
1543 // `impl [... for] Public<...>`, but not `impl [... for]
1544 // Vec<Public>` or `(Public,)`, etc.
1545 let self_is_public_path
;
1547 // Check the properties of the `Self` type:
1549 let mut visitor
= ObsoleteCheckTypeForPrivatenessVisitor
{
1551 contains_private
: false,
1552 at_outer_type
: true,
1553 outer_type_is_public_path
: false,
1555 visitor
.visit_ty(&self_ty
);
1556 self_contains_private
= visitor
.contains_private
;
1557 self_is_public_path
= visitor
.outer_type_is_public_path
;
1560 // Miscellaneous info about the impl:
1562 // `true` iff this is `impl Private for ...`.
1563 let not_private_trait
= of_trait
.as_ref().map_or(
1564 true, // no trait counts as public trait
1566 let did
= tr
.path
.res
.def_id();
1568 if let Some(did
) = did
.as_local() {
1569 self.trait_is_public(self.tcx
.hir().local_def_id_to_hir_id(did
))
1571 true // external traits must be public
1576 // `true` iff this is a trait impl or at least one method is public.
1578 // `impl Public { $( fn ...() {} )* }` is not visible.
1580 // This is required over just using the methods' privacy
1581 // directly because we might have `impl<T: Foo<Private>> ...`,
1582 // and we shouldn't warn about the generics if all the methods
1583 // are private (because `T` won't be visible externally).
1584 let trait_or_some_public_method
= of_trait
.is_some()
1585 || items
.iter().any(|impl_item_ref
| {
1586 let impl_item
= self.tcx
.hir().impl_item(impl_item_ref
.id
);
1587 match impl_item
.kind
{
1588 hir
::ImplItemKind
::Const(..) | hir
::ImplItemKind
::Fn(..) => {
1589 self.access_levels
.is_reachable(impl_item_ref
.id
.hir_id
)
1591 hir
::ImplItemKind
::TyAlias(_
) => false,
1595 if !self_contains_private
&& not_private_trait
&& trait_or_some_public_method
{
1596 intravisit
::walk_generics(self, g
);
1600 for impl_item_ref
in items
{
1601 // This is where we choose whether to walk down
1602 // further into the impl to check its items. We
1603 // should only walk into public items so that we
1604 // don't erroneously report errors for private
1605 // types in private items.
1606 let impl_item
= self.tcx
.hir().impl_item(impl_item_ref
.id
);
1607 match impl_item
.kind
{
1608 hir
::ImplItemKind
::Const(..) | hir
::ImplItemKind
::Fn(..)
1610 .item_is_public(&impl_item
.hir_id
, &impl_item
.vis
) =>
1612 intravisit
::walk_impl_item(self, impl_item
)
1614 hir
::ImplItemKind
::TyAlias(..) => {
1615 intravisit
::walk_impl_item(self, impl_item
)
1622 // Any private types in a trait impl fall into three
1624 // 1. mentioned in the trait definition
1625 // 2. mentioned in the type params/generics
1626 // 3. mentioned in the associated types of the impl
1628 // Those in 1. can only occur if the trait is in
1629 // this crate and will've been warned about on the
1630 // trait definition (there's no need to warn twice
1631 // so we don't check the methods).
1633 // Those in 2. are warned via walk_generics and this
1635 intravisit
::walk_path(self, &tr
.path
);
1637 // Those in 3. are warned with this call.
1638 for impl_item_ref
in items
{
1639 let impl_item
= self.tcx
.hir().impl_item(impl_item_ref
.id
);
1640 if let hir
::ImplItemKind
::TyAlias(ref ty
) = impl_item
.kind
{
1646 } else if of_trait
.is_none() && self_is_public_path
{
1647 // `impl Public<Private> { ... }`. Any public static
1648 // methods will be visible as `Public::foo`.
1649 let mut found_pub_static
= false;
1650 for impl_item_ref
in items
{
1651 if self.item_is_public(&impl_item_ref
.id
.hir_id
, &impl_item_ref
.vis
) {
1652 let impl_item
= self.tcx
.hir().impl_item(impl_item_ref
.id
);
1653 match impl_item_ref
.kind
{
1654 AssocItemKind
::Const
=> {
1655 found_pub_static
= true;
1656 intravisit
::walk_impl_item(self, impl_item
);
1658 AssocItemKind
::Fn { has_self: false }
=> {
1659 found_pub_static
= true;
1660 intravisit
::walk_impl_item(self, impl_item
);
1666 if found_pub_static
{
1667 intravisit
::walk_generics(self, g
)
1673 // `type ... = ...;` can contain private types, because
1674 // we're introducing a new name.
1675 hir
::ItemKind
::TyAlias(..) => return,
1677 // Not at all public, so we don't care.
1678 _
if !self.item_is_public(&item
.hir_id
, &item
.vis
) => {
1685 // We've carefully constructed it so that if we're here, then
1686 // any `visit_ty`'s will be called on things that are in
1687 // public signatures, i.e., things that we're interested in for
1689 intravisit
::walk_item(self, item
);
1692 fn visit_generics(&mut self, generics
: &'tcx hir
::Generics
<'tcx
>) {
1693 for param
in generics
.params
{
1694 for bound
in param
.bounds
{
1695 self.check_generic_bound(bound
);
1698 for predicate
in generics
.where_clause
.predicates
{
1700 hir
::WherePredicate
::BoundPredicate(bound_pred
) => {
1701 for bound
in bound_pred
.bounds
.iter() {
1702 self.check_generic_bound(bound
)
1705 hir
::WherePredicate
::RegionPredicate(_
) => {}
1706 hir
::WherePredicate
::EqPredicate(eq_pred
) => {
1707 self.visit_ty(&eq_pred
.rhs_ty
);
1713 fn visit_foreign_item(&mut self, item
: &'tcx hir
::ForeignItem
<'tcx
>) {
1714 if self.access_levels
.is_reachable(item
.hir_id
) {
1715 intravisit
::walk_foreign_item(self, item
)
1719 fn visit_ty(&mut self, t
: &'tcx hir
::Ty
<'tcx
>) {
1720 if let hir
::TyKind
::Path(hir
::QPath
::Resolved(_
, ref path
)) = t
.kind
{
1721 if self.path_is_private_type(path
) {
1722 self.old_error_set
.insert(t
.hir_id
);
1725 intravisit
::walk_ty(self, t
)
1730 v
: &'tcx hir
::Variant
<'tcx
>,
1731 g
: &'tcx hir
::Generics
<'tcx
>,
1732 item_id
: hir
::HirId
,
1734 if self.access_levels
.is_reachable(v
.id
) {
1735 self.in_variant
= true;
1736 intravisit
::walk_variant(self, v
, g
, item_id
);
1737 self.in_variant
= false;
1741 fn visit_struct_field(&mut self, s
: &'tcx hir
::StructField
<'tcx
>) {
1742 if s
.vis
.node
.is_pub() || self.in_variant
{
1743 intravisit
::walk_struct_field(self, s
);
1747 // We don't need to introspect into these at all: an
1748 // expression/block context can't possibly contain exported things.
1749 // (Making them no-ops stops us from traversing the whole AST without
1750 // having to be super careful about our `walk_...` calls above.)
1751 fn visit_block(&mut self, _
: &'tcx hir
::Block
<'tcx
>) {}
1752 fn visit_expr(&mut self, _
: &'tcx hir
::Expr
<'tcx
>) {}
1755 ///////////////////////////////////////////////////////////////////////////////
1756 /// SearchInterfaceForPrivateItemsVisitor traverses an item's interface and
1757 /// finds any private components in it.
1758 /// PrivateItemsInPublicInterfacesVisitor ensures there are no private types
1759 /// and traits in public interfaces.
1760 ///////////////////////////////////////////////////////////////////////////////
1762 struct SearchInterfaceForPrivateItemsVisitor
<'tcx
> {
1764 item_id
: hir
::HirId
,
1767 /// The visitor checks that each component type is at least this visible.
1768 required_visibility
: ty
::Visibility
,
1769 has_pub_restricted
: bool
,
1770 has_old_errors
: bool
,
1774 impl SearchInterfaceForPrivateItemsVisitor
<'tcx
> {
1775 fn generics(&mut self) -> &mut Self {
1776 for param
in &self.tcx
.generics_of(self.item_def_id
).params
{
1778 GenericParamDefKind
::Lifetime
=> {}
1779 GenericParamDefKind
::Type { has_default, .. }
=> {
1781 self.visit(self.tcx
.type_of(param
.def_id
));
1784 GenericParamDefKind
::Const
=> {
1785 self.visit(self.tcx
.type_of(param
.def_id
));
1792 fn predicates(&mut self) -> &mut Self {
1793 // N.B., we use `explicit_predicates_of` and not `predicates_of`
1794 // because we don't want to report privacy errors due to where
1795 // clauses that the compiler inferred. We only want to
1796 // consider the ones that the user wrote. This is important
1797 // for the inferred outlives rules; see
1798 // `src/test/ui/rfc-2093-infer-outlives/privacy.rs`.
1799 self.visit_predicates(self.tcx
.explicit_predicates_of(self.item_def_id
));
1803 fn ty(&mut self) -> &mut Self {
1804 self.visit(self.tcx
.type_of(self.item_def_id
));
1808 fn check_def_id(&mut self, def_id
: DefId
, kind
: &str, descr
: &dyn fmt
::Display
) -> bool
{
1809 if self.leaks_private_dep(def_id
) {
1810 self.tcx
.struct_span_lint_hir(
1811 lint
::builtin
::EXPORTED_PRIVATE_DEPENDENCIES
,
1815 lint
.build(&format
!(
1816 "{} `{}` from private dependency '{}' in public \
1820 self.tcx
.crate_name(def_id
.krate
)
1827 let hir_id
= match def_id
.as_local() {
1828 Some(def_id
) => self.tcx
.hir().local_def_id_to_hir_id(def_id
),
1829 None
=> return false,
1832 let (vis
, vis_span
, vis_descr
) = def_id_visibility(self.tcx
, def_id
);
1833 if !vis
.is_at_least(self.required_visibility
, self.tcx
) {
1834 let make_msg
= || format
!("{} {} `{}` in public interface", vis_descr
, kind
, descr
);
1835 if self.has_pub_restricted
|| self.has_old_errors
|| self.in_assoc_ty
{
1836 let mut err
= if kind
== "trait" {
1837 struct_span_err
!(self.tcx
.sess
, self.span
, E0445
, "{}", make_msg())
1839 struct_span_err
!(self.tcx
.sess
, self.span
, E0446
, "{}", make_msg())
1841 err
.span_label(self.span
, format
!("can't leak {} {}", vis_descr
, kind
));
1842 err
.span_label(vis_span
, format
!("`{}` declared as {}", descr
, vis_descr
));
1845 let err_code
= if kind
== "trait" { "E0445" }
else { "E0446" }
;
1846 self.tcx
.struct_span_lint_hir(
1847 lint
::builtin
::PRIVATE_IN_PUBLIC
,
1850 |lint
| lint
.build(&format
!("{} (error {})", make_msg(), err_code
)).emit(),
1858 /// An item is 'leaked' from a private dependency if all
1859 /// of the following are true:
1860 /// 1. It's contained within a public type
1861 /// 2. It comes from a private crate
1862 fn leaks_private_dep(&self, item_id
: DefId
) -> bool
{
1863 let ret
= self.required_visibility
== ty
::Visibility
::Public
1864 && self.tcx
.is_private_dep(item_id
.krate
);
1866 tracing
::debug
!("leaks_private_dep(item_id={:?})={}", item_id
, ret
);
1871 impl DefIdVisitor
<'tcx
> for SearchInterfaceForPrivateItemsVisitor
<'tcx
> {
1872 fn tcx(&self) -> TyCtxt
<'tcx
> {
1875 fn visit_def_id(&mut self, def_id
: DefId
, kind
: &str, descr
: &dyn fmt
::Display
) -> bool
{
1876 self.check_def_id(def_id
, kind
, descr
)
1880 struct PrivateItemsInPublicInterfacesVisitor
<'a
, 'tcx
> {
1882 has_pub_restricted
: bool
,
1883 old_error_set
: &'a HirIdSet
,
1886 impl<'a
, 'tcx
> PrivateItemsInPublicInterfacesVisitor
<'a
, 'tcx
> {
1889 item_id
: hir
::HirId
,
1890 required_visibility
: ty
::Visibility
,
1891 ) -> SearchInterfaceForPrivateItemsVisitor
<'tcx
> {
1892 let mut has_old_errors
= false;
1894 // Slow path taken only if there any errors in the crate.
1895 for &id
in self.old_error_set
{
1896 // Walk up the nodes until we find `item_id` (or we hit a root).
1900 has_old_errors
= true;
1903 let parent
= self.tcx
.hir().get_parent_node(id
);
1915 SearchInterfaceForPrivateItemsVisitor
{
1918 item_def_id
: self.tcx
.hir().local_def_id(item_id
).to_def_id(),
1919 span
: self.tcx
.hir().span(item_id
),
1920 required_visibility
,
1921 has_pub_restricted
: self.has_pub_restricted
,
1927 fn check_assoc_item(
1930 assoc_item_kind
: AssocItemKind
,
1931 defaultness
: hir
::Defaultness
,
1932 vis
: ty
::Visibility
,
1934 let mut check
= self.check(hir_id
, vis
);
1936 let (check_ty
, is_assoc_ty
) = match assoc_item_kind
{
1937 AssocItemKind
::Const
| AssocItemKind
::Fn { .. }
=> (true, false),
1938 AssocItemKind
::Type
=> (defaultness
.has_value(), true),
1940 check
.in_assoc_ty
= is_assoc_ty
;
1941 check
.generics().predicates();
1948 impl<'a
, 'tcx
> Visitor
<'tcx
> for PrivateItemsInPublicInterfacesVisitor
<'a
, 'tcx
> {
1949 type Map
= Map
<'tcx
>;
1951 fn nested_visit_map(&mut self) -> NestedVisitorMap
<Self::Map
> {
1952 NestedVisitorMap
::OnlyBodies(self.tcx
.hir())
1955 fn visit_item(&mut self, item
: &'tcx hir
::Item
<'tcx
>) {
1957 let item_visibility
= ty
::Visibility
::from_hir(&item
.vis
, item
.hir_id
, tcx
);
1960 // Crates are always public.
1961 hir
::ItemKind
::ExternCrate(..) => {}
1962 // All nested items are checked by `visit_item`.
1963 hir
::ItemKind
::Mod(..) => {}
1964 // Checked in resolve.
1965 hir
::ItemKind
::Use(..) => {}
1967 hir
::ItemKind
::GlobalAsm(..) => {}
1968 // Subitems of these items have inherited publicity.
1969 hir
::ItemKind
::Const(..)
1970 | hir
::ItemKind
::Static(..)
1971 | hir
::ItemKind
::Fn(..)
1972 | hir
::ItemKind
::TyAlias(..) => {
1973 self.check(item
.hir_id
, item_visibility
).generics().predicates().ty();
1975 hir
::ItemKind
::OpaqueTy(..) => {
1976 // `ty()` for opaque types is the underlying type,
1977 // it's not a part of interface, so we skip it.
1978 self.check(item
.hir_id
, item_visibility
).generics().predicates();
1980 hir
::ItemKind
::Trait(.., trait_item_refs
) => {
1981 self.check(item
.hir_id
, item_visibility
).generics().predicates();
1983 for trait_item_ref
in trait_item_refs
{
1984 self.check_assoc_item(
1985 trait_item_ref
.id
.hir_id
,
1986 trait_item_ref
.kind
,
1987 trait_item_ref
.defaultness
,
1992 hir
::ItemKind
::TraitAlias(..) => {
1993 self.check(item
.hir_id
, item_visibility
).generics().predicates();
1995 hir
::ItemKind
::Enum(ref def
, _
) => {
1996 self.check(item
.hir_id
, item_visibility
).generics().predicates();
1998 for variant
in def
.variants
{
1999 for field
in variant
.data
.fields() {
2000 self.check(field
.hir_id
, item_visibility
).ty();
2004 // Subitems of foreign modules have their own publicity.
2005 hir
::ItemKind
::ForeignMod(ref foreign_mod
) => {
2006 for foreign_item
in foreign_mod
.items
{
2007 let vis
= ty
::Visibility
::from_hir(&foreign_item
.vis
, item
.hir_id
, tcx
);
2008 self.check(foreign_item
.hir_id
, vis
).generics().predicates().ty();
2011 // Subitems of structs and unions have their own publicity.
2012 hir
::ItemKind
::Struct(ref struct_def
, _
) | hir
::ItemKind
::Union(ref struct_def
, _
) => {
2013 self.check(item
.hir_id
, item_visibility
).generics().predicates();
2015 for field
in struct_def
.fields() {
2016 let field_visibility
= ty
::Visibility
::from_hir(&field
.vis
, item
.hir_id
, tcx
);
2017 self.check(field
.hir_id
, min(item_visibility
, field_visibility
, tcx
)).ty();
2020 // An inherent impl is public when its type is public
2021 // Subitems of inherent impls have their own publicity.
2022 // A trait impl is public when both its type and its trait are public
2023 // Subitems of trait impls have inherited publicity.
2024 hir
::ItemKind
::Impl { ref of_trait, items, .. }
=> {
2025 let impl_vis
= ty
::Visibility
::of_impl(item
.hir_id
, tcx
, &Default
::default());
2026 self.check(item
.hir_id
, impl_vis
).generics().predicates();
2027 for impl_item_ref
in items
{
2028 let impl_item
= tcx
.hir().impl_item(impl_item_ref
.id
);
2029 let impl_item_vis
= if of_trait
.is_none() {
2031 ty
::Visibility
::from_hir(&impl_item
.vis
, item
.hir_id
, tcx
),
2038 self.check_assoc_item(
2039 impl_item_ref
.id
.hir_id
,
2041 impl_item_ref
.defaultness
,
2050 pub fn provide(providers
: &mut Providers
) {
2051 *providers
= Providers
{
2052 privacy_access_levels
,
2053 check_private_in_public
,
2059 fn check_mod_privacy(tcx
: TyCtxt
<'_
>, module_def_id
: LocalDefId
) {
2060 // Check privacy of names not checked in previous compilation stages.
2061 let mut visitor
= NamePrivacyVisitor { tcx, maybe_typeck_results: None, current_item: None }
;
2062 let (module
, span
, hir_id
) = tcx
.hir().get_module(module_def_id
);
2064 intravisit
::walk_mod(&mut visitor
, module
, hir_id
);
2066 // Check privacy of explicitly written types and traits as well as
2067 // inferred types of expressions and patterns.
2069 TypePrivacyVisitor { tcx, maybe_typeck_results: None, current_item: module_def_id, span }
;
2070 intravisit
::walk_mod(&mut visitor
, module
, hir_id
);
2073 fn privacy_access_levels(tcx
: TyCtxt
<'_
>, krate
: CrateNum
) -> &AccessLevels
{
2074 assert_eq
!(krate
, LOCAL_CRATE
);
2076 // Build up a set of all exported items in the AST. This is a set of all
2077 // items which are reachable from external crates based on visibility.
2078 let mut visitor
= EmbargoVisitor
{
2080 access_levels
: Default
::default(),
2081 macro_reachable
: Default
::default(),
2082 prev_level
: Some(AccessLevel
::Public
),
2086 intravisit
::walk_crate(&mut visitor
, tcx
.hir().krate());
2087 if visitor
.changed
{
2088 visitor
.changed
= false;
2093 visitor
.update(hir
::CRATE_HIR_ID
, Some(AccessLevel
::Public
));
2095 tcx
.arena
.alloc(visitor
.access_levels
)
2098 fn check_private_in_public(tcx
: TyCtxt
<'_
>, krate
: CrateNum
) {
2099 assert_eq
!(krate
, LOCAL_CRATE
);
2101 let access_levels
= tcx
.privacy_access_levels(LOCAL_CRATE
);
2103 let krate
= tcx
.hir().krate();
2105 let mut visitor
= ObsoleteVisiblePrivateTypesVisitor
{
2107 access_levels
: &access_levels
,
2109 old_error_set
: Default
::default(),
2111 intravisit
::walk_crate(&mut visitor
, krate
);
2113 let has_pub_restricted
= {
2114 let mut pub_restricted_visitor
= PubRestrictedVisitor { tcx, has_pub_restricted: false }
;
2115 intravisit
::walk_crate(&mut pub_restricted_visitor
, krate
);
2116 pub_restricted_visitor
.has_pub_restricted
2119 // Check for private types and traits in public interfaces.
2120 let mut visitor
= PrivateItemsInPublicInterfacesVisitor
{
2123 old_error_set
: &visitor
.old_error_set
,
2125 krate
.visit_all_item_likes(&mut DeepVisitor
::new(&mut visitor
));