]> git.proxmox.com Git - rustc.git/blob - src/librustc_privacy/lib.rs
New upstream version 1.34.2+dfsg1
[rustc.git] / src / librustc_privacy / lib.rs
1 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
2
3 #![deny(rust_2018_idioms)]
4
5 #![feature(nll)]
6 #![feature(rustc_diagnostic_macros)]
7
8 #![recursion_limit="256"]
9
10 #[macro_use] extern crate syntax;
11
12 use rustc::bug;
13 use rustc::hir::{self, Node, PatKind, AssociatedItemKind};
14 use rustc::hir::def::Def;
15 use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, CrateNum, DefId};
16 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
17 use rustc::hir::itemlikevisit::DeepVisitor;
18 use rustc::lint;
19 use rustc::middle::privacy::{AccessLevel, AccessLevels};
20 use rustc::ty::{self, TyCtxt, Ty, TraitRef, TypeFoldable, GenericParamDefKind};
21 use rustc::ty::fold::TypeVisitor;
22 use rustc::ty::query::Providers;
23 use rustc::ty::subst::Substs;
24 use rustc::util::nodemap::NodeSet;
25 use rustc_data_structures::fx::FxHashSet;
26 use rustc_data_structures::sync::Lrc;
27 use syntax::ast::{self, DUMMY_NODE_ID, Ident};
28 use syntax::attr;
29 use syntax::symbol::keywords;
30 use syntax_pos::Span;
31
32 use std::{cmp, fmt, mem};
33 use std::marker::PhantomData;
34
35 mod diagnostics;
36
37 ////////////////////////////////////////////////////////////////////////////////
38 /// Generic infrastructure used to implement specific visitors below.
39 ////////////////////////////////////////////////////////////////////////////////
40
41 /// Implemented to visit all `DefId`s in a type.
42 /// Visiting `DefId`s is useful because visibilities and reachabilities are attached to them.
43 /// The idea is to visit "all components of a type", as documented in
44 /// https://github.com/rust-lang/rfcs/blob/master/text/2145-type-privacy.md#how-to-determine-visibility-of-a-type.
45 /// The default type visitor (`TypeVisitor`) does most of the job, but it has some shortcomings.
46 /// First, it doesn't have overridable `fn visit_trait_ref`, so we have to catch trait `DefId`s
47 /// manually. Second, it doesn't visit some type components like signatures of fn types, or traits
48 /// in `impl Trait`, see individual comments in `DefIdVisitorSkeleton::visit_ty`.
49 trait DefIdVisitor<'a, 'tcx: 'a> {
50 fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx>;
51 fn shallow(&self) -> bool { false }
52 fn skip_assoc_tys(&self) -> bool { false }
53 fn visit_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool;
54
55 /// Not overridden, but used to actually visit types and traits.
56 fn skeleton(&mut self) -> DefIdVisitorSkeleton<'_, 'a, 'tcx, Self> {
57 DefIdVisitorSkeleton {
58 def_id_visitor: self,
59 visited_opaque_tys: Default::default(),
60 dummy: Default::default(),
61 }
62 }
63 fn visit(&mut self, ty_fragment: impl TypeFoldable<'tcx>) -> bool {
64 ty_fragment.visit_with(&mut self.skeleton())
65 }
66 fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> bool {
67 self.skeleton().visit_trait(trait_ref)
68 }
69 fn visit_predicates(&mut self, predicates: Lrc<ty::GenericPredicates<'tcx>>) -> bool {
70 self.skeleton().visit_predicates(predicates)
71 }
72 }
73
74 struct DefIdVisitorSkeleton<'v, 'a, 'tcx, V>
75 where V: DefIdVisitor<'a, 'tcx> + ?Sized
76 {
77 def_id_visitor: &'v mut V,
78 visited_opaque_tys: FxHashSet<DefId>,
79 dummy: PhantomData<TyCtxt<'a, 'tcx, 'tcx>>,
80 }
81
82 impl<'a, 'tcx, V> DefIdVisitorSkeleton<'_, 'a, 'tcx, V>
83 where V: DefIdVisitor<'a, 'tcx> + ?Sized
84 {
85 fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> bool {
86 let TraitRef { def_id, substs } = trait_ref;
87 self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref) ||
88 (!self.def_id_visitor.shallow() && substs.visit_with(self))
89 }
90
91 fn visit_predicates(&mut self, predicates: Lrc<ty::GenericPredicates<'tcx>>) -> bool {
92 let ty::GenericPredicates { parent: _, predicates } = &*predicates;
93 for (predicate, _span) in predicates {
94 match predicate {
95 ty::Predicate::Trait(poly_predicate) => {
96 let ty::TraitPredicate { trait_ref } = *poly_predicate.skip_binder();
97 if self.visit_trait(trait_ref) {
98 return true;
99 }
100 }
101 ty::Predicate::Projection(poly_predicate) => {
102 let ty::ProjectionPredicate { projection_ty, ty } =
103 *poly_predicate.skip_binder();
104 if ty.visit_with(self) {
105 return true;
106 }
107 if self.visit_trait(projection_ty.trait_ref(self.def_id_visitor.tcx())) {
108 return true;
109 }
110 }
111 ty::Predicate::TypeOutlives(poly_predicate) => {
112 let ty::OutlivesPredicate(ty, _region) = *poly_predicate.skip_binder();
113 if ty.visit_with(self) {
114 return true;
115 }
116 }
117 ty::Predicate::RegionOutlives(..) => {},
118 _ => bug!("unexpected predicate: {:?}", predicate),
119 }
120 }
121 false
122 }
123 }
124
125 impl<'a, 'tcx, V> TypeVisitor<'tcx> for DefIdVisitorSkeleton<'_, 'a, 'tcx, V>
126 where V: DefIdVisitor<'a, 'tcx> + ?Sized
127 {
128 fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
129 let tcx = self.def_id_visitor.tcx();
130 // Substs are not visited here because they are visited below in `super_visit_with`.
131 match ty.sty {
132 ty::Adt(&ty::AdtDef { did: def_id, .. }, ..) |
133 ty::Foreign(def_id) |
134 ty::FnDef(def_id, ..) |
135 ty::Closure(def_id, ..) |
136 ty::Generator(def_id, ..) => {
137 if self.def_id_visitor.visit_def_id(def_id, "type", ty) {
138 return true;
139 }
140 if self.def_id_visitor.shallow() {
141 return false;
142 }
143 // Default type visitor doesn't visit signatures of fn types.
144 // Something like `fn() -> Priv {my_func}` is considered a private type even if
145 // `my_func` is public, so we need to visit signatures.
146 if let ty::FnDef(..) = ty.sty {
147 if tcx.fn_sig(def_id).visit_with(self) {
148 return true;
149 }
150 }
151 // Inherent static methods don't have self type in substs.
152 // Something like `fn() {my_method}` type of the method
153 // `impl Pub<Priv> { pub fn my_method() {} }` is considered a private type,
154 // so we need to visit the self type additionally.
155 if let Some(assoc_item) = tcx.opt_associated_item(def_id) {
156 if let ty::ImplContainer(impl_def_id) = assoc_item.container {
157 if tcx.type_of(impl_def_id).visit_with(self) {
158 return true;
159 }
160 }
161 }
162 }
163 ty::Projection(proj) | ty::UnnormalizedProjection(proj) => {
164 if self.def_id_visitor.skip_assoc_tys() {
165 // Visitors searching for minimal visibility/reachability want to
166 // conservatively approximate associated types like `<Type as Trait>::Alias`
167 // as visible/reachable even if both `Type` and `Trait` are private.
168 // Ideally, associated types should be substituted in the same way as
169 // free type aliases, but this isn't done yet.
170 return false;
171 }
172 // This will also visit substs if necessary, so we don't need to recurse.
173 return self.visit_trait(proj.trait_ref(tcx));
174 }
175 ty::Dynamic(predicates, ..) => {
176 // All traits in the list are considered the "primary" part of the type
177 // and are visited by shallow visitors.
178 for predicate in *predicates.skip_binder() {
179 let trait_ref = match *predicate {
180 ty::ExistentialPredicate::Trait(trait_ref) => trait_ref,
181 ty::ExistentialPredicate::Projection(proj) => proj.trait_ref(tcx),
182 ty::ExistentialPredicate::AutoTrait(def_id) =>
183 ty::ExistentialTraitRef { def_id, substs: Substs::empty() },
184 };
185 let ty::ExistentialTraitRef { def_id, substs: _ } = trait_ref;
186 if self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref) {
187 return true;
188 }
189 }
190 }
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)) {
202 return true;
203 }
204 }
205 }
206 // These types don't have their own def-ids (but may have subcomponents
207 // with def-ids that should be visited recursively).
208 ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) |
209 ty::Float(..) | ty::Str | ty::Never |
210 ty::Array(..) | ty::Slice(..) | ty::Tuple(..) |
211 ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) |
212 ty::Param(..) | ty::Error | ty::GeneratorWitness(..) => {}
213 ty::Bound(..) | ty::Placeholder(..) | ty::Infer(..) =>
214 bug!("unexpected type: {:?}", ty),
215 }
216
217 !self.def_id_visitor.shallow() && ty.super_visit_with(self)
218 }
219 }
220
221 fn def_id_visibility<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
222 -> (ty::Visibility, Span, &'static str) {
223 match tcx.hir().as_local_node_id(def_id) {
224 Some(node_id) => {
225 let vis = match tcx.hir().get(node_id) {
226 Node::Item(item) => &item.vis,
227 Node::ForeignItem(foreign_item) => &foreign_item.vis,
228 Node::TraitItem(..) | Node::Variant(..) => {
229 return def_id_visibility(tcx, tcx.hir().get_parent_did(node_id));
230 }
231 Node::ImplItem(impl_item) => {
232 match tcx.hir().get(tcx.hir().get_parent(node_id)) {
233 Node::Item(item) => match &item.node {
234 hir::ItemKind::Impl(.., None, _, _) => &impl_item.vis,
235 hir::ItemKind::Impl(.., Some(trait_ref), _, _)
236 => return def_id_visibility(tcx, trait_ref.path.def.def_id()),
237 kind => bug!("unexpected item kind: {:?}", kind),
238 }
239 node => bug!("unexpected node kind: {:?}", node),
240 }
241 }
242 Node::StructCtor(vdata) => {
243 let struct_node_id = tcx.hir().get_parent(node_id);
244 let item = match tcx.hir().get(struct_node_id) {
245 Node::Item(item) => item,
246 node => bug!("unexpected node kind: {:?}", node),
247 };
248 let (mut ctor_vis, mut span, mut descr) =
249 (ty::Visibility::from_hir(&item.vis, struct_node_id, tcx),
250 item.vis.span, item.vis.node.descr());
251 for field in vdata.fields() {
252 let field_vis = ty::Visibility::from_hir(&field.vis, node_id, tcx);
253 if ctor_vis.is_at_least(field_vis, tcx) {
254 ctor_vis = field_vis;
255 span = field.vis.span;
256 descr = field.vis.node.descr();
257 }
258 }
259
260 // If the structure is marked as non_exhaustive then lower the
261 // visibility to within the crate.
262 if ctor_vis == ty::Visibility::Public {
263 let adt_def = tcx.adt_def(tcx.hir().get_parent_did(node_id));
264 if adt_def.non_enum_variant().is_field_list_non_exhaustive() {
265 ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
266 span = attr::find_by_name(&item.attrs, "non_exhaustive").unwrap().span;
267 descr = "crate-visible";
268 }
269 }
270
271 return (ctor_vis, span, descr);
272 }
273 Node::Expr(expr) => {
274 return (ty::Visibility::Restricted(tcx.hir().get_module_parent(expr.id)),
275 expr.span, "private")
276 }
277 node => bug!("unexpected node kind: {:?}", node)
278 };
279 (ty::Visibility::from_hir(vis, node_id, tcx), vis.span, vis.node.descr())
280 }
281 None => {
282 let vis = tcx.visibility(def_id);
283 let descr = if vis == ty::Visibility::Public { "public" } else { "private" };
284 (vis, tcx.def_span(def_id), descr)
285 }
286 }
287 }
288
289 // Set the correct `TypeckTables` for the given `item_id` (or an empty table if
290 // there is no `TypeckTables` for the item).
291 fn item_tables<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
292 node_id: ast::NodeId,
293 empty_tables: &'a ty::TypeckTables<'tcx>)
294 -> &'a ty::TypeckTables<'tcx> {
295 let def_id = tcx.hir().local_def_id(node_id);
296 if tcx.has_typeck_tables(def_id) { tcx.typeck_tables_of(def_id) } else { empty_tables }
297 }
298
299 fn min<'a, 'tcx>(vis1: ty::Visibility, vis2: ty::Visibility, tcx: TyCtxt<'a, 'tcx, 'tcx>)
300 -> ty::Visibility {
301 if vis1.is_at_least(vis2, tcx) { vis2 } else { vis1 }
302 }
303
304 ////////////////////////////////////////////////////////////////////////////////
305 /// Visitor used to determine if pub(restricted) is used anywhere in the crate.
306 ///
307 /// This is done so that `private_in_public` warnings can be turned into hard errors
308 /// in crates that have been updated to use pub(restricted).
309 ////////////////////////////////////////////////////////////////////////////////
310 struct PubRestrictedVisitor<'a, 'tcx: 'a> {
311 tcx: TyCtxt<'a, 'tcx, 'tcx>,
312 has_pub_restricted: bool,
313 }
314
315 impl<'a, 'tcx> Visitor<'tcx> for PubRestrictedVisitor<'a, 'tcx> {
316 fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
317 NestedVisitorMap::All(&self.tcx.hir())
318 }
319 fn visit_vis(&mut self, vis: &'tcx hir::Visibility) {
320 self.has_pub_restricted = self.has_pub_restricted || vis.node.is_pub_restricted();
321 }
322 }
323
324 ////////////////////////////////////////////////////////////////////////////////
325 /// Visitor used to determine impl visibility and reachability.
326 ////////////////////////////////////////////////////////////////////////////////
327
328 struct FindMin<'a, 'tcx, VL: VisibilityLike> {
329 tcx: TyCtxt<'a, 'tcx, 'tcx>,
330 access_levels: &'a AccessLevels,
331 min: VL,
332 }
333
334 impl<'a, 'tcx, VL: VisibilityLike> DefIdVisitor<'a, 'tcx> for FindMin<'a, 'tcx, VL> {
335 fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { self.tcx }
336 fn shallow(&self) -> bool { VL::SHALLOW }
337 fn skip_assoc_tys(&self) -> bool { true }
338 fn visit_def_id(&mut self, def_id: DefId, _kind: &str, _descr: &dyn fmt::Display) -> bool {
339 self.min = VL::new_min(self, def_id);
340 false
341 }
342 }
343
344 trait VisibilityLike: Sized {
345 const MAX: Self;
346 const SHALLOW: bool = false;
347 fn new_min<'a, 'tcx>(find: &FindMin<'a, 'tcx, Self>, def_id: DefId) -> Self;
348
349 // Returns an over-approximation (`skip_assoc_tys` = true) of visibility due to
350 // associated types for which we can't determine visibility precisely.
351 fn of_impl<'a, 'tcx>(node_id: ast::NodeId, tcx: TyCtxt<'a, 'tcx, 'tcx>,
352 access_levels: &'a AccessLevels) -> Self {
353 let mut find = FindMin { tcx, access_levels, min: Self::MAX };
354 let def_id = tcx.hir().local_def_id(node_id);
355 find.visit(tcx.type_of(def_id));
356 if let Some(trait_ref) = tcx.impl_trait_ref(def_id) {
357 find.visit_trait(trait_ref);
358 }
359 find.min
360 }
361 }
362 impl VisibilityLike for ty::Visibility {
363 const MAX: Self = ty::Visibility::Public;
364 fn new_min<'a, 'tcx>(find: &FindMin<'a, 'tcx, Self>, def_id: DefId) -> Self {
365 min(def_id_visibility(find.tcx, def_id).0, find.min, find.tcx)
366 }
367 }
368 impl VisibilityLike for Option<AccessLevel> {
369 const MAX: Self = Some(AccessLevel::Public);
370 // Type inference is very smart sometimes.
371 // It can make an impl reachable even some components of its type or trait are unreachable.
372 // E.g. methods of `impl ReachableTrait<UnreachableTy> for ReachableTy<UnreachableTy> { ... }`
373 // can be usable from other crates (#57264). So we skip substs when calculating reachability
374 // and consider an impl reachable if its "shallow" type and trait are reachable.
375 //
376 // The assumption we make here is that type-inference won't let you use an impl without knowing
377 // both "shallow" version of its self type and "shallow" version of its trait if it exists
378 // (which require reaching the `DefId`s in them).
379 const SHALLOW: bool = true;
380 fn new_min<'a, 'tcx>(find: &FindMin<'a, 'tcx, Self>, def_id: DefId) -> Self {
381 cmp::min(if let Some(node_id) = find.tcx.hir().as_local_node_id(def_id) {
382 find.access_levels.map.get(&node_id).cloned()
383 } else {
384 Self::MAX
385 }, find.min)
386 }
387 }
388
389 ////////////////////////////////////////////////////////////////////////////////
390 /// The embargo visitor, used to determine the exports of the AST.
391 ////////////////////////////////////////////////////////////////////////////////
392
393 struct EmbargoVisitor<'a, 'tcx: 'a> {
394 tcx: TyCtxt<'a, 'tcx, 'tcx>,
395
396 // Accessibility levels for reachable nodes.
397 access_levels: AccessLevels,
398 // Previous accessibility level; `None` means unreachable.
399 prev_level: Option<AccessLevel>,
400 // Has something changed in the level map?
401 changed: bool,
402 }
403
404 struct ReachEverythingInTheInterfaceVisitor<'b, 'a: 'b, 'tcx: 'a> {
405 access_level: Option<AccessLevel>,
406 item_def_id: DefId,
407 ev: &'b mut EmbargoVisitor<'a, 'tcx>,
408 }
409
410 impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
411 fn get(&self, id: ast::NodeId) -> Option<AccessLevel> {
412 self.access_levels.map.get(&id).cloned()
413 }
414
415 // Updates node level and returns the updated level.
416 fn update(&mut self, id: ast::NodeId, level: Option<AccessLevel>) -> Option<AccessLevel> {
417 let old_level = self.get(id);
418 // Accessibility levels can only grow.
419 if level > old_level {
420 self.access_levels.map.insert(id, level.unwrap());
421 self.changed = true;
422 level
423 } else {
424 old_level
425 }
426 }
427
428 fn reach(&mut self, item_id: ast::NodeId, access_level: Option<AccessLevel>)
429 -> ReachEverythingInTheInterfaceVisitor<'_, 'a, 'tcx> {
430 ReachEverythingInTheInterfaceVisitor {
431 access_level: cmp::min(access_level, Some(AccessLevel::Reachable)),
432 item_def_id: self.tcx.hir().local_def_id(item_id),
433 ev: self,
434 }
435 }
436
437
438 /// Given the path segments of a `ItemKind::Use`, then we need
439 /// to update the visibility of the intermediate use so that it isn't linted
440 /// by `unreachable_pub`.
441 ///
442 /// This isn't trivial as `path.def` has the `DefId` of the eventual target
443 /// of the use statement not of the next intermediate use statement.
444 ///
445 /// To do this, consider the last two segments of the path to our intermediate
446 /// use statement. We expect the penultimate segment to be a module and the
447 /// last segment to be the name of the item we are exporting. We can then
448 /// look at the items contained in the module for the use statement with that
449 /// name and update that item's visibility.
450 ///
451 /// FIXME: This solution won't work with glob imports and doesn't respect
452 /// namespaces. See <https://github.com/rust-lang/rust/pull/57922#discussion_r251234202>.
453 fn update_visibility_of_intermediate_use_statements(&mut self, segments: &[hir::PathSegment]) {
454 if let Some([module, segment]) = segments.rchunks_exact(2).next() {
455 if let Some(item) = module.def
456 .and_then(|def| def.mod_def_id())
457 .and_then(|def_id| self.tcx.hir().as_local_hir_id(def_id))
458 .map(|module_hir_id| self.tcx.hir().expect_item_by_hir_id(module_hir_id))
459 {
460 if let hir::ItemKind::Mod(m) = &item.node {
461 for item_id in m.item_ids.as_ref() {
462 let item = self.tcx.hir().expect_item(item_id.id);
463 let def_id = self.tcx.hir().local_def_id(item_id.id);
464 if !self.tcx.hygienic_eq(segment.ident, item.ident, def_id) { continue; }
465 if let hir::ItemKind::Use(..) = item.node {
466 self.update(item.id, Some(AccessLevel::Exported));
467 }
468 }
469 }
470 }
471 }
472 }
473 }
474
475 impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
476 /// We want to visit items in the context of their containing
477 /// module and so forth, so supply a crate for doing a deep walk.
478 fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
479 NestedVisitorMap::All(&self.tcx.hir())
480 }
481
482 fn visit_item(&mut self, item: &'tcx hir::Item) {
483 let inherited_item_level = match item.node {
484 hir::ItemKind::Impl(..) =>
485 Option::<AccessLevel>::of_impl(item.id, self.tcx, &self.access_levels),
486 // Foreign modules inherit level from parents.
487 hir::ItemKind::ForeignMod(..) => self.prev_level,
488 // Other `pub` items inherit levels from parents.
489 hir::ItemKind::Const(..) | hir::ItemKind::Enum(..) | hir::ItemKind::ExternCrate(..) |
490 hir::ItemKind::GlobalAsm(..) | hir::ItemKind::Fn(..) | hir::ItemKind::Mod(..) |
491 hir::ItemKind::Static(..) | hir::ItemKind::Struct(..) |
492 hir::ItemKind::Trait(..) | hir::ItemKind::TraitAlias(..) |
493 hir::ItemKind::Existential(..) |
494 hir::ItemKind::Ty(..) | hir::ItemKind::Union(..) | hir::ItemKind::Use(..) => {
495 if item.vis.node.is_pub() { self.prev_level } else { None }
496 }
497 };
498
499 // Update level of the item itself.
500 let item_level = self.update(item.id, inherited_item_level);
501
502 // Update levels of nested things.
503 match item.node {
504 hir::ItemKind::Enum(ref def, _) => {
505 for variant in &def.variants {
506 let variant_level = self.update(variant.node.data.id(), item_level);
507 for field in variant.node.data.fields() {
508 self.update(field.id, variant_level);
509 }
510 }
511 }
512 hir::ItemKind::Impl(.., ref trait_ref, _, ref impl_item_refs) => {
513 for impl_item_ref in impl_item_refs {
514 if trait_ref.is_some() || impl_item_ref.vis.node.is_pub() {
515 self.update(impl_item_ref.id.node_id, item_level);
516 }
517 }
518 }
519 hir::ItemKind::Trait(.., ref trait_item_refs) => {
520 for trait_item_ref in trait_item_refs {
521 self.update(trait_item_ref.id.node_id, item_level);
522 }
523 }
524 hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => {
525 if !def.is_struct() {
526 self.update(def.id(), item_level);
527 }
528 for field in def.fields() {
529 if field.vis.node.is_pub() {
530 self.update(field.id, item_level);
531 }
532 }
533 }
534 hir::ItemKind::ForeignMod(ref foreign_mod) => {
535 for foreign_item in &foreign_mod.items {
536 if foreign_item.vis.node.is_pub() {
537 self.update(foreign_item.id, item_level);
538 }
539 }
540 }
541 hir::ItemKind::Existential(..) |
542 hir::ItemKind::Use(..) |
543 hir::ItemKind::Static(..) |
544 hir::ItemKind::Const(..) |
545 hir::ItemKind::GlobalAsm(..) |
546 hir::ItemKind::Ty(..) |
547 hir::ItemKind::Mod(..) |
548 hir::ItemKind::TraitAlias(..) |
549 hir::ItemKind::Fn(..) |
550 hir::ItemKind::ExternCrate(..) => {}
551 }
552
553 // Mark all items in interfaces of reachable items as reachable.
554 match item.node {
555 // The interface is empty.
556 hir::ItemKind::ExternCrate(..) => {}
557 // All nested items are checked by `visit_item`.
558 hir::ItemKind::Mod(..) => {}
559 // Re-exports are handled in `visit_mod`. However, in order to avoid looping over
560 // all of the items of a mod in `visit_mod` looking for use statements, we handle
561 // making sure that intermediate use statements have their visibilities updated here.
562 hir::ItemKind::Use(ref path, _) => {
563 if item_level.is_some() {
564 self.update_visibility_of_intermediate_use_statements(path.segments.as_ref());
565 }
566 }
567 // The interface is empty.
568 hir::ItemKind::GlobalAsm(..) => {}
569 hir::ItemKind::Existential(..) => {
570 // FIXME: This is some serious pessimization intended to workaround deficiencies
571 // in the reachability pass (`middle/reachable.rs`). Types are marked as link-time
572 // reachable if they are returned via `impl Trait`, even from private functions.
573 let exist_level = cmp::max(item_level, Some(AccessLevel::ReachableFromImplTrait));
574 self.reach(item.id, exist_level).generics().predicates().ty();
575 }
576 // Visit everything.
577 hir::ItemKind::Const(..) | hir::ItemKind::Static(..) |
578 hir::ItemKind::Fn(..) | hir::ItemKind::Ty(..) => {
579 if item_level.is_some() {
580 self.reach(item.id, item_level).generics().predicates().ty();
581 }
582 }
583 hir::ItemKind::Trait(.., ref trait_item_refs) => {
584 if item_level.is_some() {
585 self.reach(item.id, item_level).generics().predicates();
586
587 for trait_item_ref in trait_item_refs {
588 let mut reach = self.reach(trait_item_ref.id.node_id, item_level);
589 reach.generics().predicates();
590
591 if trait_item_ref.kind == AssociatedItemKind::Type &&
592 !trait_item_ref.defaultness.has_value() {
593 // No type to visit.
594 } else {
595 reach.ty();
596 }
597 }
598 }
599 }
600 hir::ItemKind::TraitAlias(..) => {
601 if item_level.is_some() {
602 self.reach(item.id, item_level).generics().predicates();
603 }
604 }
605 // Visit everything except for private impl items.
606 hir::ItemKind::Impl(.., ref impl_item_refs) => {
607 if item_level.is_some() {
608 self.reach(item.id, item_level).generics().predicates().ty().trait_ref();
609
610 for impl_item_ref in impl_item_refs {
611 let impl_item_level = self.get(impl_item_ref.id.node_id);
612 if impl_item_level.is_some() {
613 self.reach(impl_item_ref.id.node_id, impl_item_level)
614 .generics().predicates().ty();
615 }
616 }
617 }
618 }
619
620 // Visit everything, but enum variants have their own levels.
621 hir::ItemKind::Enum(ref def, _) => {
622 if item_level.is_some() {
623 self.reach(item.id, item_level).generics().predicates();
624 }
625 for variant in &def.variants {
626 let variant_level = self.get(variant.node.data.id());
627 if variant_level.is_some() {
628 for field in variant.node.data.fields() {
629 self.reach(field.id, variant_level).ty();
630 }
631 // Corner case: if the variant is reachable, but its
632 // enum is not, make the enum reachable as well.
633 self.update(item.id, variant_level);
634 }
635 }
636 }
637 // Visit everything, but foreign items have their own levels.
638 hir::ItemKind::ForeignMod(ref foreign_mod) => {
639 for foreign_item in &foreign_mod.items {
640 let foreign_item_level = self.get(foreign_item.id);
641 if foreign_item_level.is_some() {
642 self.reach(foreign_item.id, foreign_item_level)
643 .generics().predicates().ty();
644 }
645 }
646 }
647 // Visit everything except for private fields.
648 hir::ItemKind::Struct(ref struct_def, _) |
649 hir::ItemKind::Union(ref struct_def, _) => {
650 if item_level.is_some() {
651 self.reach(item.id, item_level).generics().predicates();
652 for field in struct_def.fields() {
653 let field_level = self.get(field.id);
654 if field_level.is_some() {
655 self.reach(field.id, field_level).ty();
656 }
657 }
658 }
659 }
660 }
661
662 let orig_level = mem::replace(&mut self.prev_level, item_level);
663 intravisit::walk_item(self, item);
664 self.prev_level = orig_level;
665 }
666
667 fn visit_block(&mut self, b: &'tcx hir::Block) {
668 // Blocks can have public items, for example impls, but they always
669 // start as completely private regardless of publicity of a function,
670 // constant, type, field, etc., in which this block resides.
671 let orig_level = mem::replace(&mut self.prev_level, None);
672 intravisit::walk_block(self, b);
673 self.prev_level = orig_level;
674 }
675
676 fn visit_mod(&mut self, m: &'tcx hir::Mod, _sp: Span, id: hir::HirId) {
677 // This code is here instead of in visit_item so that the
678 // crate module gets processed as well.
679 if self.prev_level.is_some() {
680 let def_id = self.tcx.hir().local_def_id_from_hir_id(id);
681 if let Some(exports) = self.tcx.module_exports(def_id) {
682 for export in exports.iter() {
683 if export.vis == ty::Visibility::Public {
684 if let Some(def_id) = export.def.opt_def_id() {
685 if let Some(node_id) = self.tcx.hir().as_local_node_id(def_id) {
686 self.update(node_id, Some(AccessLevel::Exported));
687 }
688 }
689 }
690 }
691 }
692 }
693
694 intravisit::walk_mod(self, m, id);
695 }
696
697 fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef) {
698 if md.legacy {
699 self.update(md.id, Some(AccessLevel::Public));
700 return
701 }
702
703 let module_did = ty::DefIdTree::parent(
704 self.tcx,
705 self.tcx.hir().local_def_id(md.id)
706 ).unwrap();
707 let mut module_id = self.tcx.hir().as_local_node_id(module_did).unwrap();
708 let level = if md.vis.node.is_pub() { self.get(module_id) } else { None };
709 let level = self.update(md.id, level);
710 if level.is_none() {
711 return
712 }
713
714 loop {
715 let module = if module_id == ast::CRATE_NODE_ID {
716 &self.tcx.hir().krate().module
717 } else if let hir::ItemKind::Mod(ref module) =
718 self.tcx.hir().expect_item(module_id).node {
719 module
720 } else {
721 unreachable!()
722 };
723 for id in &module.item_ids {
724 self.update(id.id, level);
725 }
726 let def_id = self.tcx.hir().local_def_id(module_id);
727 if let Some(exports) = self.tcx.module_exports(def_id) {
728 for export in exports.iter() {
729 if let Some(node_id) = self.tcx.hir().as_local_node_id(export.def.def_id()) {
730 self.update(node_id, level);
731 }
732 }
733 }
734
735 if module_id == ast::CRATE_NODE_ID {
736 break
737 }
738 module_id = self.tcx.hir().get_parent_node(module_id);
739 }
740 }
741 }
742
743 impl<'a, 'tcx> ReachEverythingInTheInterfaceVisitor<'_, 'a, 'tcx> {
744 fn generics(&mut self) -> &mut Self {
745 for param in &self.ev.tcx.generics_of(self.item_def_id).params {
746 match param.kind {
747 GenericParamDefKind::Type { has_default, .. } => {
748 if has_default {
749 self.visit(self.ev.tcx.type_of(param.def_id));
750 }
751 }
752 GenericParamDefKind::Lifetime => {}
753 }
754 }
755 self
756 }
757
758 fn predicates(&mut self) -> &mut Self {
759 self.visit_predicates(self.ev.tcx.predicates_of(self.item_def_id));
760 self
761 }
762
763 fn ty(&mut self) -> &mut Self {
764 self.visit(self.ev.tcx.type_of(self.item_def_id));
765 self
766 }
767
768 fn trait_ref(&mut self) -> &mut Self {
769 if let Some(trait_ref) = self.ev.tcx.impl_trait_ref(self.item_def_id) {
770 self.visit_trait(trait_ref);
771 }
772 self
773 }
774 }
775
776 impl<'a, 'tcx> DefIdVisitor<'a, 'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'a, 'tcx> {
777 fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { self.ev.tcx }
778 fn visit_def_id(&mut self, def_id: DefId, _kind: &str, _descr: &dyn fmt::Display) -> bool {
779 if let Some(node_id) = self.ev.tcx.hir().as_local_node_id(def_id) {
780 self.ev.update(node_id, self.access_level);
781 }
782 false
783 }
784 }
785
786 //////////////////////////////////////////////////////////////////////////////////////
787 /// Name privacy visitor, checks privacy and reports violations.
788 /// Most of name privacy checks are performed during the main resolution phase,
789 /// or later in type checking when field accesses and associated items are resolved.
790 /// This pass performs remaining checks for fields in struct expressions and patterns.
791 //////////////////////////////////////////////////////////////////////////////////////
792
793 struct NamePrivacyVisitor<'a, 'tcx: 'a> {
794 tcx: TyCtxt<'a, 'tcx, 'tcx>,
795 tables: &'a ty::TypeckTables<'tcx>,
796 current_item: ast::NodeId,
797 empty_tables: &'a ty::TypeckTables<'tcx>,
798 }
799
800 impl<'a, 'tcx> NamePrivacyVisitor<'a, 'tcx> {
801 // Checks that a field in a struct constructor (expression or pattern) is accessible.
802 fn check_field(&mut self,
803 use_ctxt: Span, // syntax context of the field name at the use site
804 span: Span, // span of the field pattern, e.g., `x: 0`
805 def: &'tcx ty::AdtDef, // definition of the struct or enum
806 field: &'tcx ty::FieldDef) { // definition of the field
807 let ident = Ident::new(keywords::Invalid.name(), use_ctxt);
808 let current_hir = self.tcx.hir().node_to_hir_id(self.current_item);
809 let def_id = self.tcx.adjust_ident(ident, def.did, current_hir).1;
810 if !def.is_enum() && !field.vis.is_accessible_from(def_id, self.tcx) {
811 struct_span_err!(self.tcx.sess, span, E0451, "field `{}` of {} `{}` is private",
812 field.ident, def.variant_descr(), self.tcx.item_path_str(def.did))
813 .span_label(span, format!("field `{}` is private", field.ident))
814 .emit();
815 }
816 }
817 }
818
819 impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> {
820 /// We want to visit items in the context of their containing
821 /// module and so forth, so supply a crate for doing a deep walk.
822 fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
823 NestedVisitorMap::All(&self.tcx.hir())
824 }
825
826 fn visit_mod(&mut self, _m: &'tcx hir::Mod, _s: Span, _n: hir::HirId) {
827 // Don't visit nested modules, since we run a separate visitor walk
828 // for each module in `privacy_access_levels`
829 }
830
831 fn visit_nested_body(&mut self, body: hir::BodyId) {
832 let orig_tables = mem::replace(&mut self.tables, self.tcx.body_tables(body));
833 let body = self.tcx.hir().body(body);
834 self.visit_body(body);
835 self.tables = orig_tables;
836 }
837
838 fn visit_item(&mut self, item: &'tcx hir::Item) {
839 let orig_current_item = mem::replace(&mut self.current_item, item.id);
840 let orig_tables =
841 mem::replace(&mut self.tables, item_tables(self.tcx, item.id, self.empty_tables));
842 intravisit::walk_item(self, item);
843 self.current_item = orig_current_item;
844 self.tables = orig_tables;
845 }
846
847 fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) {
848 let orig_tables =
849 mem::replace(&mut self.tables, item_tables(self.tcx, ti.id, self.empty_tables));
850 intravisit::walk_trait_item(self, ti);
851 self.tables = orig_tables;
852 }
853
854 fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) {
855 let orig_tables =
856 mem::replace(&mut self.tables, item_tables(self.tcx, ii.id, self.empty_tables));
857 intravisit::walk_impl_item(self, ii);
858 self.tables = orig_tables;
859 }
860
861 fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
862 match expr.node {
863 hir::ExprKind::Struct(ref qpath, ref fields, ref base) => {
864 let def = self.tables.qpath_def(qpath, expr.hir_id);
865 let adt = self.tables.expr_ty(expr).ty_adt_def().unwrap();
866 let variant = adt.variant_of_def(def);
867 if let Some(ref base) = *base {
868 // If the expression uses FRU we need to make sure all the unmentioned fields
869 // are checked for privacy (RFC 736). Rather than computing the set of
870 // unmentioned fields, just check them all.
871 for (vf_index, variant_field) in variant.fields.iter().enumerate() {
872 let field = fields.iter().find(|f| {
873 self.tcx.field_index(f.id, self.tables) == vf_index
874 });
875 let (use_ctxt, span) = match field {
876 Some(field) => (field.ident.span, field.span),
877 None => (base.span, base.span),
878 };
879 self.check_field(use_ctxt, span, adt, variant_field);
880 }
881 } else {
882 for field in fields {
883 let use_ctxt = field.ident.span;
884 let index = self.tcx.field_index(field.id, self.tables);
885 self.check_field(use_ctxt, field.span, adt, &variant.fields[index]);
886 }
887 }
888 }
889 _ => {}
890 }
891
892 intravisit::walk_expr(self, expr);
893 }
894
895 fn visit_pat(&mut self, pat: &'tcx hir::Pat) {
896 match pat.node {
897 PatKind::Struct(ref qpath, ref fields, _) => {
898 let def = self.tables.qpath_def(qpath, pat.hir_id);
899 let adt = self.tables.pat_ty(pat).ty_adt_def().unwrap();
900 let variant = adt.variant_of_def(def);
901 for field in fields {
902 let use_ctxt = field.node.ident.span;
903 let index = self.tcx.field_index(field.node.id, self.tables);
904 self.check_field(use_ctxt, field.span, adt, &variant.fields[index]);
905 }
906 }
907 _ => {}
908 }
909
910 intravisit::walk_pat(self, pat);
911 }
912 }
913
914 ////////////////////////////////////////////////////////////////////////////////////////////
915 /// Type privacy visitor, checks types for privacy and reports violations.
916 /// Both explicitly written types and inferred types of expressions and patters are checked.
917 /// Checks are performed on "semantic" types regardless of names and their hygiene.
918 ////////////////////////////////////////////////////////////////////////////////////////////
919
920 struct TypePrivacyVisitor<'a, 'tcx: 'a> {
921 tcx: TyCtxt<'a, 'tcx, 'tcx>,
922 tables: &'a ty::TypeckTables<'tcx>,
923 current_item: DefId,
924 in_body: bool,
925 span: Span,
926 empty_tables: &'a ty::TypeckTables<'tcx>,
927 }
928
929 impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> {
930 fn item_is_accessible(&self, did: DefId) -> bool {
931 def_id_visibility(self.tcx, did).0.is_accessible_from(self.current_item, self.tcx)
932 }
933
934 // Take node-id of an expression or pattern and check its type for privacy.
935 fn check_expr_pat_type(&mut self, id: hir::HirId, span: Span) -> bool {
936 self.span = span;
937 if self.visit(self.tables.node_type(id)) || self.visit(self.tables.node_substs(id)) {
938 return true;
939 }
940 if let Some(adjustments) = self.tables.adjustments().get(id) {
941 for adjustment in adjustments {
942 if self.visit(adjustment.target) {
943 return true;
944 }
945 }
946 }
947 false
948 }
949
950 fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
951 let is_error = !self.item_is_accessible(def_id);
952 if is_error {
953 self.tcx.sess.span_err(self.span, &format!("{} `{}` is private", kind, descr));
954 }
955 is_error
956 }
957 }
958
959 impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
960 /// We want to visit items in the context of their containing
961 /// module and so forth, so supply a crate for doing a deep walk.
962 fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
963 NestedVisitorMap::All(&self.tcx.hir())
964 }
965
966 fn visit_mod(&mut self, _m: &'tcx hir::Mod, _s: Span, _n: hir::HirId) {
967 // Don't visit nested modules, since we run a separate visitor walk
968 // for each module in `privacy_access_levels`
969 }
970
971 fn visit_nested_body(&mut self, body: hir::BodyId) {
972 let orig_tables = mem::replace(&mut self.tables, self.tcx.body_tables(body));
973 let orig_in_body = mem::replace(&mut self.in_body, true);
974 let body = self.tcx.hir().body(body);
975 self.visit_body(body);
976 self.tables = orig_tables;
977 self.in_body = orig_in_body;
978 }
979
980 fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty) {
981 self.span = hir_ty.span;
982 if self.in_body {
983 // Types in bodies.
984 if self.visit(self.tables.node_type(hir_ty.hir_id)) {
985 return;
986 }
987 } else {
988 // Types in signatures.
989 // FIXME: This is very ineffective. Ideally each HIR type should be converted
990 // into a semantic type only once and the result should be cached somehow.
991 if self.visit(rustc_typeck::hir_ty_to_ty(self.tcx, hir_ty)) {
992 return;
993 }
994 }
995
996 intravisit::walk_ty(self, hir_ty);
997 }
998
999 fn visit_trait_ref(&mut self, trait_ref: &'tcx hir::TraitRef) {
1000 self.span = trait_ref.path.span;
1001 if !self.in_body {
1002 // Avoid calling `hir_trait_to_predicates` in bodies, it will ICE.
1003 // The traits' privacy in bodies is already checked as a part of trait object types.
1004 let (principal, projections) =
1005 rustc_typeck::hir_trait_to_predicates(self.tcx, trait_ref);
1006 if self.visit_trait(*principal.skip_binder()) {
1007 return;
1008 }
1009 for (poly_predicate, _) in projections {
1010 let tcx = self.tcx;
1011 if self.visit(poly_predicate.skip_binder().ty) ||
1012 self.visit_trait(poly_predicate.skip_binder().projection_ty.trait_ref(tcx)) {
1013 return;
1014 }
1015 }
1016 }
1017
1018 intravisit::walk_trait_ref(self, trait_ref);
1019 }
1020
1021 // Check types of expressions
1022 fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
1023 if self.check_expr_pat_type(expr.hir_id, expr.span) {
1024 // Do not check nested expressions if the error already happened.
1025 return;
1026 }
1027 match expr.node {
1028 hir::ExprKind::Assign(.., ref rhs) | hir::ExprKind::Match(ref rhs, ..) => {
1029 // Do not report duplicate errors for `x = y` and `match x { ... }`.
1030 if self.check_expr_pat_type(rhs.hir_id, rhs.span) {
1031 return;
1032 }
1033 }
1034 hir::ExprKind::MethodCall(_, span, _) => {
1035 // Method calls have to be checked specially.
1036 self.span = span;
1037 if let Some(def) = self.tables.type_dependent_defs().get(expr.hir_id) {
1038 if self.visit(self.tcx.type_of(def.def_id())) {
1039 return;
1040 }
1041 } else {
1042 self.tcx.sess.delay_span_bug(expr.span,
1043 "no type-dependent def for method call");
1044 }
1045 }
1046 _ => {}
1047 }
1048
1049 intravisit::walk_expr(self, expr);
1050 }
1051
1052 // Prohibit access to associated items with insufficient nominal visibility.
1053 //
1054 // Additionally, until better reachability analysis for macros 2.0 is available,
1055 // we prohibit access to private statics from other crates, this allows to give
1056 // more code internal visibility at link time. (Access to private functions
1057 // is already prohibited by type privacy for function types.)
1058 fn visit_qpath(&mut self, qpath: &'tcx hir::QPath, id: hir::HirId, span: Span) {
1059 let def = match *qpath {
1060 hir::QPath::Resolved(_, ref path) => match path.def {
1061 Def::Method(..) | Def::AssociatedConst(..) |
1062 Def::AssociatedTy(..) | Def::AssociatedExistential(..) |
1063 Def::Static(..) => Some(path.def),
1064 _ => None,
1065 }
1066 hir::QPath::TypeRelative(..) => {
1067 self.tables.type_dependent_defs().get(id).cloned()
1068 }
1069 };
1070 if let Some(def) = def {
1071 let def_id = def.def_id();
1072 let is_local_static = if let Def::Static(..) = def { def_id.is_local() } else { false };
1073 if !self.item_is_accessible(def_id) && !is_local_static {
1074 let name = match *qpath {
1075 hir::QPath::Resolved(_, ref path) => path.to_string(),
1076 hir::QPath::TypeRelative(_, ref segment) => segment.ident.to_string(),
1077 };
1078 let msg = format!("{} `{}` is private", def.kind_name(), name);
1079 self.tcx.sess.span_err(span, &msg);
1080 return;
1081 }
1082 }
1083
1084 intravisit::walk_qpath(self, qpath, id, span);
1085 }
1086
1087 // Check types of patterns.
1088 fn visit_pat(&mut self, pattern: &'tcx hir::Pat) {
1089 if self.check_expr_pat_type(pattern.hir_id, pattern.span) {
1090 // Do not check nested patterns if the error already happened.
1091 return;
1092 }
1093
1094 intravisit::walk_pat(self, pattern);
1095 }
1096
1097 fn visit_local(&mut self, local: &'tcx hir::Local) {
1098 if let Some(ref init) = local.init {
1099 if self.check_expr_pat_type(init.hir_id, init.span) {
1100 // Do not report duplicate errors for `let x = y`.
1101 return;
1102 }
1103 }
1104
1105 intravisit::walk_local(self, local);
1106 }
1107
1108 // Check types in item interfaces.
1109 fn visit_item(&mut self, item: &'tcx hir::Item) {
1110 let orig_current_item =
1111 mem::replace(&mut self.current_item, self.tcx.hir().local_def_id(item.id));
1112 let orig_in_body = mem::replace(&mut self.in_body, false);
1113 let orig_tables =
1114 mem::replace(&mut self.tables, item_tables(self.tcx, item.id, self.empty_tables));
1115 intravisit::walk_item(self, item);
1116 self.tables = orig_tables;
1117 self.in_body = orig_in_body;
1118 self.current_item = orig_current_item;
1119 }
1120
1121 fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) {
1122 let orig_tables =
1123 mem::replace(&mut self.tables, item_tables(self.tcx, ti.id, self.empty_tables));
1124 intravisit::walk_trait_item(self, ti);
1125 self.tables = orig_tables;
1126 }
1127
1128 fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) {
1129 let orig_tables =
1130 mem::replace(&mut self.tables, item_tables(self.tcx, ii.id, self.empty_tables));
1131 intravisit::walk_impl_item(self, ii);
1132 self.tables = orig_tables;
1133 }
1134 }
1135
1136 impl<'a, 'tcx> DefIdVisitor<'a, 'tcx> for TypePrivacyVisitor<'a, 'tcx> {
1137 fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { self.tcx }
1138 fn visit_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
1139 self.check_def_id(def_id, kind, descr)
1140 }
1141 }
1142
1143 ///////////////////////////////////////////////////////////////////////////////
1144 /// Obsolete visitors for checking for private items in public interfaces.
1145 /// These visitors are supposed to be kept in frozen state and produce an
1146 /// "old error node set". For backward compatibility the new visitor reports
1147 /// warnings instead of hard errors when the erroneous node is not in this old set.
1148 ///////////////////////////////////////////////////////////////////////////////
1149
1150 struct ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx: 'a> {
1151 tcx: TyCtxt<'a, 'tcx, 'tcx>,
1152 access_levels: &'a AccessLevels,
1153 in_variant: bool,
1154 // Set of errors produced by this obsolete visitor.
1155 old_error_set: NodeSet,
1156 }
1157
1158 struct ObsoleteCheckTypeForPrivatenessVisitor<'a, 'b: 'a, 'tcx: 'b> {
1159 inner: &'a ObsoleteVisiblePrivateTypesVisitor<'b, 'tcx>,
1160 /// Whether the type refers to private types.
1161 contains_private: bool,
1162 /// Whether we've recurred at all (i.e., if we're pointing at the
1163 /// first type on which `visit_ty` was called).
1164 at_outer_type: bool,
1165 /// Whether that first type is a public path.
1166 outer_type_is_public_path: bool,
1167 }
1168
1169 impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
1170 fn path_is_private_type(&self, path: &hir::Path) -> bool {
1171 let did = match path.def {
1172 Def::PrimTy(..) | Def::SelfTy(..) | Def::Err => return false,
1173 def => def.def_id(),
1174 };
1175
1176 // A path can only be private if:
1177 // it's in this crate...
1178 if let Some(node_id) = self.tcx.hir().as_local_node_id(did) {
1179 // .. and it corresponds to a private type in the AST (this returns
1180 // `None` for type parameters).
1181 match self.tcx.hir().find(node_id) {
1182 Some(Node::Item(ref item)) => !item.vis.node.is_pub(),
1183 Some(_) | None => false,
1184 }
1185 } else {
1186 return false
1187 }
1188 }
1189
1190 fn trait_is_public(&self, trait_id: ast::NodeId) -> bool {
1191 // FIXME: this would preferably be using `exported_items`, but all
1192 // traits are exported currently (see `EmbargoVisitor.exported_trait`).
1193 self.access_levels.is_public(trait_id)
1194 }
1195
1196 fn check_generic_bound(&mut self, bound: &hir::GenericBound) {
1197 if let hir::GenericBound::Trait(ref trait_ref, _) = *bound {
1198 if self.path_is_private_type(&trait_ref.trait_ref.path) {
1199 self.old_error_set.insert(trait_ref.trait_ref.ref_id);
1200 }
1201 }
1202 }
1203
1204 fn item_is_public(&self, id: &ast::NodeId, vis: &hir::Visibility) -> bool {
1205 self.access_levels.is_reachable(*id) || vis.node.is_pub()
1206 }
1207 }
1208
1209 impl<'a, 'b, 'tcx, 'v> Visitor<'v> for ObsoleteCheckTypeForPrivatenessVisitor<'a, 'b, 'tcx> {
1210 fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
1211 NestedVisitorMap::None
1212 }
1213
1214 fn visit_ty(&mut self, ty: &hir::Ty) {
1215 if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = ty.node {
1216 if self.inner.path_is_private_type(path) {
1217 self.contains_private = true;
1218 // Found what we're looking for, so let's stop working.
1219 return
1220 }
1221 }
1222 if let hir::TyKind::Path(_) = ty.node {
1223 if self.at_outer_type {
1224 self.outer_type_is_public_path = true;
1225 }
1226 }
1227 self.at_outer_type = false;
1228 intravisit::walk_ty(self, ty)
1229 }
1230
1231 // Don't want to recurse into `[, .. expr]`.
1232 fn visit_expr(&mut self, _: &hir::Expr) {}
1233 }
1234
1235 impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
1236 /// We want to visit items in the context of their containing
1237 /// module and so forth, so supply a crate for doing a deep walk.
1238 fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
1239 NestedVisitorMap::All(&self.tcx.hir())
1240 }
1241
1242 fn visit_item(&mut self, item: &'tcx hir::Item) {
1243 match item.node {
1244 // Contents of a private mod can be re-exported, so we need
1245 // to check internals.
1246 hir::ItemKind::Mod(_) => {}
1247
1248 // An `extern {}` doesn't introduce a new privacy
1249 // namespace (the contents have their own privacies).
1250 hir::ItemKind::ForeignMod(_) => {}
1251
1252 hir::ItemKind::Trait(.., ref bounds, _) => {
1253 if !self.trait_is_public(item.id) {
1254 return
1255 }
1256
1257 for bound in bounds.iter() {
1258 self.check_generic_bound(bound)
1259 }
1260 }
1261
1262 // Impls need some special handling to try to offer useful
1263 // error messages without (too many) false positives
1264 // (i.e., we could just return here to not check them at
1265 // all, or some worse estimation of whether an impl is
1266 // publicly visible).
1267 hir::ItemKind::Impl(.., ref g, ref trait_ref, ref self_, ref impl_item_refs) => {
1268 // `impl [... for] Private` is never visible.
1269 let self_contains_private;
1270 // `impl [... for] Public<...>`, but not `impl [... for]
1271 // Vec<Public>` or `(Public,)`, etc.
1272 let self_is_public_path;
1273
1274 // Check the properties of the `Self` type:
1275 {
1276 let mut visitor = ObsoleteCheckTypeForPrivatenessVisitor {
1277 inner: self,
1278 contains_private: false,
1279 at_outer_type: true,
1280 outer_type_is_public_path: false,
1281 };
1282 visitor.visit_ty(&self_);
1283 self_contains_private = visitor.contains_private;
1284 self_is_public_path = visitor.outer_type_is_public_path;
1285 }
1286
1287 // Miscellaneous info about the impl:
1288
1289 // `true` iff this is `impl Private for ...`.
1290 let not_private_trait =
1291 trait_ref.as_ref().map_or(true, // no trait counts as public trait
1292 |tr| {
1293 let did = tr.path.def.def_id();
1294
1295 if let Some(node_id) = self.tcx.hir().as_local_node_id(did) {
1296 self.trait_is_public(node_id)
1297 } else {
1298 true // external traits must be public
1299 }
1300 });
1301
1302 // `true` iff this is a trait impl or at least one method is public.
1303 //
1304 // `impl Public { $( fn ...() {} )* }` is not visible.
1305 //
1306 // This is required over just using the methods' privacy
1307 // directly because we might have `impl<T: Foo<Private>> ...`,
1308 // and we shouldn't warn about the generics if all the methods
1309 // are private (because `T` won't be visible externally).
1310 let trait_or_some_public_method =
1311 trait_ref.is_some() ||
1312 impl_item_refs.iter()
1313 .any(|impl_item_ref| {
1314 let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
1315 match impl_item.node {
1316 hir::ImplItemKind::Const(..) |
1317 hir::ImplItemKind::Method(..) => {
1318 self.access_levels.is_reachable(impl_item.id)
1319 }
1320 hir::ImplItemKind::Existential(..) |
1321 hir::ImplItemKind::Type(_) => false,
1322 }
1323 });
1324
1325 if !self_contains_private &&
1326 not_private_trait &&
1327 trait_or_some_public_method {
1328
1329 intravisit::walk_generics(self, g);
1330
1331 match *trait_ref {
1332 None => {
1333 for impl_item_ref in impl_item_refs {
1334 // This is where we choose whether to walk down
1335 // further into the impl to check its items. We
1336 // should only walk into public items so that we
1337 // don't erroneously report errors for private
1338 // types in private items.
1339 let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
1340 match impl_item.node {
1341 hir::ImplItemKind::Const(..) |
1342 hir::ImplItemKind::Method(..)
1343 if self.item_is_public(&impl_item.id, &impl_item.vis) =>
1344 {
1345 intravisit::walk_impl_item(self, impl_item)
1346 }
1347 hir::ImplItemKind::Type(..) => {
1348 intravisit::walk_impl_item(self, impl_item)
1349 }
1350 _ => {}
1351 }
1352 }
1353 }
1354 Some(ref tr) => {
1355 // Any private types in a trait impl fall into three
1356 // categories.
1357 // 1. mentioned in the trait definition
1358 // 2. mentioned in the type params/generics
1359 // 3. mentioned in the associated types of the impl
1360 //
1361 // Those in 1. can only occur if the trait is in
1362 // this crate and will've been warned about on the
1363 // trait definition (there's no need to warn twice
1364 // so we don't check the methods).
1365 //
1366 // Those in 2. are warned via walk_generics and this
1367 // call here.
1368 intravisit::walk_path(self, &tr.path);
1369
1370 // Those in 3. are warned with this call.
1371 for impl_item_ref in impl_item_refs {
1372 let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
1373 if let hir::ImplItemKind::Type(ref ty) = impl_item.node {
1374 self.visit_ty(ty);
1375 }
1376 }
1377 }
1378 }
1379 } else if trait_ref.is_none() && self_is_public_path {
1380 // `impl Public<Private> { ... }`. Any public static
1381 // methods will be visible as `Public::foo`.
1382 let mut found_pub_static = false;
1383 for impl_item_ref in impl_item_refs {
1384 if self.item_is_public(&impl_item_ref.id.node_id, &impl_item_ref.vis) {
1385 let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
1386 match impl_item_ref.kind {
1387 AssociatedItemKind::Const => {
1388 found_pub_static = true;
1389 intravisit::walk_impl_item(self, impl_item);
1390 }
1391 AssociatedItemKind::Method { has_self: false } => {
1392 found_pub_static = true;
1393 intravisit::walk_impl_item(self, impl_item);
1394 }
1395 _ => {}
1396 }
1397 }
1398 }
1399 if found_pub_static {
1400 intravisit::walk_generics(self, g)
1401 }
1402 }
1403 return
1404 }
1405
1406 // `type ... = ...;` can contain private types, because
1407 // we're introducing a new name.
1408 hir::ItemKind::Ty(..) => return,
1409
1410 // Not at all public, so we don't care.
1411 _ if !self.item_is_public(&item.id, &item.vis) => {
1412 return;
1413 }
1414
1415 _ => {}
1416 }
1417
1418 // We've carefully constructed it so that if we're here, then
1419 // any `visit_ty`'s will be called on things that are in
1420 // public signatures, i.e., things that we're interested in for
1421 // this visitor.
1422 intravisit::walk_item(self, item);
1423 }
1424
1425 fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
1426 for param in &generics.params {
1427 for bound in &param.bounds {
1428 self.check_generic_bound(bound);
1429 }
1430 }
1431 for predicate in &generics.where_clause.predicates {
1432 match predicate {
1433 hir::WherePredicate::BoundPredicate(bound_pred) => {
1434 for bound in bound_pred.bounds.iter() {
1435 self.check_generic_bound(bound)
1436 }
1437 }
1438 hir::WherePredicate::RegionPredicate(_) => {}
1439 hir::WherePredicate::EqPredicate(eq_pred) => {
1440 self.visit_ty(&eq_pred.rhs_ty);
1441 }
1442 }
1443 }
1444 }
1445
1446 fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) {
1447 if self.access_levels.is_reachable(item.id) {
1448 intravisit::walk_foreign_item(self, item)
1449 }
1450 }
1451
1452 fn visit_ty(&mut self, t: &'tcx hir::Ty) {
1453 if let hir::TyKind::Path(hir::QPath::Resolved(_, ref path)) = t.node {
1454 if self.path_is_private_type(path) {
1455 self.old_error_set.insert(t.id);
1456 }
1457 }
1458 intravisit::walk_ty(self, t)
1459 }
1460
1461 fn visit_variant(&mut self,
1462 v: &'tcx hir::Variant,
1463 g: &'tcx hir::Generics,
1464 item_id: hir::HirId) {
1465 if self.access_levels.is_reachable(v.node.data.id()) {
1466 self.in_variant = true;
1467 intravisit::walk_variant(self, v, g, item_id);
1468 self.in_variant = false;
1469 }
1470 }
1471
1472 fn visit_struct_field(&mut self, s: &'tcx hir::StructField) {
1473 if s.vis.node.is_pub() || self.in_variant {
1474 intravisit::walk_struct_field(self, s);
1475 }
1476 }
1477
1478 // We don't need to introspect into these at all: an
1479 // expression/block context can't possibly contain exported things.
1480 // (Making them no-ops stops us from traversing the whole AST without
1481 // having to be super careful about our `walk_...` calls above.)
1482 fn visit_block(&mut self, _: &'tcx hir::Block) {}
1483 fn visit_expr(&mut self, _: &'tcx hir::Expr) {}
1484 }
1485
1486 ///////////////////////////////////////////////////////////////////////////////
1487 /// SearchInterfaceForPrivateItemsVisitor traverses an item's interface and
1488 /// finds any private components in it.
1489 /// PrivateItemsInPublicInterfacesVisitor ensures there are no private types
1490 /// and traits in public interfaces.
1491 ///////////////////////////////////////////////////////////////////////////////
1492
1493 struct SearchInterfaceForPrivateItemsVisitor<'a, 'tcx: 'a> {
1494 tcx: TyCtxt<'a, 'tcx, 'tcx>,
1495 item_id: ast::NodeId,
1496 item_def_id: DefId,
1497 span: Span,
1498 /// The visitor checks that each component type is at least this visible.
1499 required_visibility: ty::Visibility,
1500 has_pub_restricted: bool,
1501 has_old_errors: bool,
1502 in_assoc_ty: bool,
1503 private_crates: FxHashSet<CrateNum>
1504 }
1505
1506 impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
1507 fn generics(&mut self) -> &mut Self {
1508 for param in &self.tcx.generics_of(self.item_def_id).params {
1509 match param.kind {
1510 GenericParamDefKind::Type { has_default, .. } => {
1511 if has_default {
1512 self.visit(self.tcx.type_of(param.def_id));
1513 }
1514 }
1515 GenericParamDefKind::Lifetime => {}
1516 }
1517 }
1518 self
1519 }
1520
1521 fn predicates(&mut self) -> &mut Self {
1522 // N.B., we use `explicit_predicates_of` and not `predicates_of`
1523 // because we don't want to report privacy errors due to where
1524 // clauses that the compiler inferred. We only want to
1525 // consider the ones that the user wrote. This is important
1526 // for the inferred outlives rules; see
1527 // `src/test/ui/rfc-2093-infer-outlives/privacy.rs`.
1528 self.visit_predicates(self.tcx.explicit_predicates_of(self.item_def_id));
1529 self
1530 }
1531
1532 fn ty(&mut self) -> &mut Self {
1533 self.visit(self.tcx.type_of(self.item_def_id));
1534 self
1535 }
1536
1537 fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
1538 if self.leaks_private_dep(def_id) {
1539 self.tcx.lint_node(lint::builtin::EXPORTED_PRIVATE_DEPENDENCIES,
1540 self.item_id,
1541 self.span,
1542 &format!("{} `{}` from private dependency '{}' in public \
1543 interface", kind, descr,
1544 self.tcx.crate_name(def_id.krate)));
1545
1546 }
1547
1548 let node_id = match self.tcx.hir().as_local_node_id(def_id) {
1549 Some(node_id) => node_id,
1550 None => return false,
1551 };
1552
1553 let (vis, vis_span, vis_descr) = def_id_visibility(self.tcx, def_id);
1554 if !vis.is_at_least(self.required_visibility, self.tcx) {
1555 let msg = format!("{} {} `{}` in public interface", vis_descr, kind, descr);
1556 if self.has_pub_restricted || self.has_old_errors || self.in_assoc_ty {
1557 let mut err = if kind == "trait" {
1558 struct_span_err!(self.tcx.sess, self.span, E0445, "{}", msg)
1559 } else {
1560 struct_span_err!(self.tcx.sess, self.span, E0446, "{}", msg)
1561 };
1562 err.span_label(self.span, format!("can't leak {} {}", vis_descr, kind));
1563 err.span_label(vis_span, format!("`{}` declared as {}", descr, vis_descr));
1564 err.emit();
1565 } else {
1566 let err_code = if kind == "trait" { "E0445" } else { "E0446" };
1567 self.tcx.lint_node(lint::builtin::PRIVATE_IN_PUBLIC, node_id, self.span,
1568 &format!("{} (error {})", msg, err_code));
1569 }
1570
1571 }
1572
1573 false
1574 }
1575
1576 /// An item is 'leaked' from a private dependency if all
1577 /// of the following are true:
1578 /// 1. It's contained within a public type
1579 /// 2. It comes from a private crate
1580 fn leaks_private_dep(&self, item_id: DefId) -> bool {
1581 let ret = self.required_visibility == ty::Visibility::Public &&
1582 self.private_crates.contains(&item_id.krate);
1583
1584 log::debug!("leaks_private_dep(item_id={:?})={}", item_id, ret);
1585 return ret;
1586 }
1587 }
1588
1589 impl<'a, 'tcx> DefIdVisitor<'a, 'tcx> for SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
1590 fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { self.tcx }
1591 fn visit_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
1592 self.check_def_id(def_id, kind, descr)
1593 }
1594 }
1595
1596 struct PrivateItemsInPublicInterfacesVisitor<'a, 'tcx: 'a> {
1597 tcx: TyCtxt<'a, 'tcx, 'tcx>,
1598 has_pub_restricted: bool,
1599 old_error_set: &'a NodeSet,
1600 private_crates: FxHashSet<CrateNum>
1601 }
1602
1603 impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
1604 fn check(&self, item_id: ast::NodeId, required_visibility: ty::Visibility)
1605 -> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
1606 let mut has_old_errors = false;
1607
1608 // Slow path taken only if there any errors in the crate.
1609 for &id in self.old_error_set {
1610 // Walk up the nodes until we find `item_id` (or we hit a root).
1611 let mut id = id;
1612 loop {
1613 if id == item_id {
1614 has_old_errors = true;
1615 break;
1616 }
1617 let parent = self.tcx.hir().get_parent_node(id);
1618 if parent == id {
1619 break;
1620 }
1621 id = parent;
1622 }
1623
1624 if has_old_errors {
1625 break;
1626 }
1627 }
1628
1629 SearchInterfaceForPrivateItemsVisitor {
1630 tcx: self.tcx,
1631 item_id,
1632 item_def_id: self.tcx.hir().local_def_id(item_id),
1633 span: self.tcx.hir().span(item_id),
1634 required_visibility,
1635 has_pub_restricted: self.has_pub_restricted,
1636 has_old_errors,
1637 in_assoc_ty: false,
1638 private_crates: self.private_crates.clone()
1639 }
1640 }
1641
1642 fn check_trait_or_impl_item(&self, node_id: ast::NodeId, assoc_item_kind: AssociatedItemKind,
1643 defaultness: hir::Defaultness, vis: ty::Visibility) {
1644 let mut check = self.check(node_id, vis);
1645
1646 let (check_ty, is_assoc_ty) = match assoc_item_kind {
1647 AssociatedItemKind::Const | AssociatedItemKind::Method { .. } => (true, false),
1648 AssociatedItemKind::Type => (defaultness.has_value(), true),
1649 // `ty()` for existential types is the underlying type,
1650 // it's not a part of interface, so we skip it.
1651 AssociatedItemKind::Existential => (false, true),
1652 };
1653 check.in_assoc_ty = is_assoc_ty;
1654 check.generics().predicates();
1655 if check_ty {
1656 check.ty();
1657 }
1658 }
1659 }
1660
1661 impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
1662 fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
1663 NestedVisitorMap::OnlyBodies(&self.tcx.hir())
1664 }
1665
1666 fn visit_item(&mut self, item: &'tcx hir::Item) {
1667 let tcx = self.tcx;
1668 let item_visibility = ty::Visibility::from_hir(&item.vis, item.id, tcx);
1669
1670 match item.node {
1671 // Crates are always public.
1672 hir::ItemKind::ExternCrate(..) => {}
1673 // All nested items are checked by `visit_item`.
1674 hir::ItemKind::Mod(..) => {}
1675 // Checked in resolve.
1676 hir::ItemKind::Use(..) => {}
1677 // No subitems.
1678 hir::ItemKind::GlobalAsm(..) => {}
1679 // Subitems of these items have inherited publicity.
1680 hir::ItemKind::Const(..) | hir::ItemKind::Static(..) |
1681 hir::ItemKind::Fn(..) | hir::ItemKind::Ty(..) => {
1682 self.check(item.id, item_visibility).generics().predicates().ty();
1683 }
1684 hir::ItemKind::Existential(..) => {
1685 // `ty()` for existential types is the underlying type,
1686 // it's not a part of interface, so we skip it.
1687 self.check(item.id, item_visibility).generics().predicates();
1688 }
1689 hir::ItemKind::Trait(.., ref trait_item_refs) => {
1690 self.check(item.id, item_visibility).generics().predicates();
1691
1692 for trait_item_ref in trait_item_refs {
1693 self.check_trait_or_impl_item(trait_item_ref.id.node_id, trait_item_ref.kind,
1694 trait_item_ref.defaultness, item_visibility);
1695 }
1696 }
1697 hir::ItemKind::TraitAlias(..) => {
1698 self.check(item.id, item_visibility).generics().predicates();
1699 }
1700 hir::ItemKind::Enum(ref def, _) => {
1701 self.check(item.id, item_visibility).generics().predicates();
1702
1703 for variant in &def.variants {
1704 for field in variant.node.data.fields() {
1705 self.check(field.id, item_visibility).ty();
1706 }
1707 }
1708 }
1709 // Subitems of foreign modules have their own publicity.
1710 hir::ItemKind::ForeignMod(ref foreign_mod) => {
1711 for foreign_item in &foreign_mod.items {
1712 let vis = ty::Visibility::from_hir(&foreign_item.vis, item.id, tcx);
1713 self.check(foreign_item.id, vis).generics().predicates().ty();
1714 }
1715 }
1716 // Subitems of structs and unions have their own publicity.
1717 hir::ItemKind::Struct(ref struct_def, _) |
1718 hir::ItemKind::Union(ref struct_def, _) => {
1719 self.check(item.id, item_visibility).generics().predicates();
1720
1721 for field in struct_def.fields() {
1722 let field_visibility = ty::Visibility::from_hir(&field.vis, item.id, tcx);
1723 self.check(field.id, min(item_visibility, field_visibility, tcx)).ty();
1724 }
1725 }
1726 // An inherent impl is public when its type is public
1727 // Subitems of inherent impls have their own publicity.
1728 // A trait impl is public when both its type and its trait are public
1729 // Subitems of trait impls have inherited publicity.
1730 hir::ItemKind::Impl(.., ref trait_ref, _, ref impl_item_refs) => {
1731 let impl_vis = ty::Visibility::of_impl(item.id, tcx, &Default::default());
1732 self.check(item.id, impl_vis).generics().predicates();
1733 for impl_item_ref in impl_item_refs {
1734 let impl_item = tcx.hir().impl_item(impl_item_ref.id);
1735 let impl_item_vis = if trait_ref.is_none() {
1736 min(ty::Visibility::from_hir(&impl_item.vis, item.id, tcx), impl_vis, tcx)
1737 } else {
1738 impl_vis
1739 };
1740 self.check_trait_or_impl_item(impl_item_ref.id.node_id, impl_item_ref.kind,
1741 impl_item_ref.defaultness, impl_item_vis);
1742 }
1743 }
1744 }
1745 }
1746 }
1747
1748 pub fn provide(providers: &mut Providers<'_>) {
1749 *providers = Providers {
1750 privacy_access_levels,
1751 check_mod_privacy,
1752 ..*providers
1753 };
1754 }
1755
1756 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Lrc<AccessLevels> {
1757 tcx.privacy_access_levels(LOCAL_CRATE)
1758 }
1759
1760 fn check_mod_privacy<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, module_def_id: DefId) {
1761 let empty_tables = ty::TypeckTables::empty(None);
1762
1763
1764 // Check privacy of names not checked in previous compilation stages.
1765 let mut visitor = NamePrivacyVisitor {
1766 tcx,
1767 tables: &empty_tables,
1768 current_item: DUMMY_NODE_ID,
1769 empty_tables: &empty_tables,
1770 };
1771 let (module, span, node_id) = tcx.hir().get_module(module_def_id);
1772 let hir_id = tcx.hir().node_to_hir_id(node_id);
1773 intravisit::walk_mod(&mut visitor, module, hir_id);
1774
1775 // Check privacy of explicitly written types and traits as well as
1776 // inferred types of expressions and patterns.
1777 let mut visitor = TypePrivacyVisitor {
1778 tcx,
1779 tables: &empty_tables,
1780 current_item: module_def_id,
1781 in_body: false,
1782 span,
1783 empty_tables: &empty_tables,
1784 };
1785 intravisit::walk_mod(&mut visitor, module, hir_id);
1786 }
1787
1788 fn privacy_access_levels<'tcx>(
1789 tcx: TyCtxt<'_, 'tcx, 'tcx>,
1790 krate: CrateNum,
1791 ) -> Lrc<AccessLevels> {
1792 assert_eq!(krate, LOCAL_CRATE);
1793
1794 let krate = tcx.hir().krate();
1795
1796 for &module in krate.modules.keys() {
1797 tcx.ensure().check_mod_privacy(tcx.hir().local_def_id(module));
1798 }
1799
1800 let private_crates: FxHashSet<CrateNum> = tcx.sess.opts.extern_private.iter()
1801 .flat_map(|c| {
1802 tcx.crates().iter().find(|&&krate| &tcx.crate_name(krate) == c).cloned()
1803 }).collect();
1804
1805
1806 // Build up a set of all exported items in the AST. This is a set of all
1807 // items which are reachable from external crates based on visibility.
1808 let mut visitor = EmbargoVisitor {
1809 tcx,
1810 access_levels: Default::default(),
1811 prev_level: Some(AccessLevel::Public),
1812 changed: false,
1813 };
1814 loop {
1815 intravisit::walk_crate(&mut visitor, krate);
1816 if visitor.changed {
1817 visitor.changed = false;
1818 } else {
1819 break
1820 }
1821 }
1822 visitor.update(ast::CRATE_NODE_ID, Some(AccessLevel::Public));
1823
1824 {
1825 let mut visitor = ObsoleteVisiblePrivateTypesVisitor {
1826 tcx,
1827 access_levels: &visitor.access_levels,
1828 in_variant: false,
1829 old_error_set: Default::default(),
1830 };
1831 intravisit::walk_crate(&mut visitor, krate);
1832
1833
1834 let has_pub_restricted = {
1835 let mut pub_restricted_visitor = PubRestrictedVisitor {
1836 tcx,
1837 has_pub_restricted: false
1838 };
1839 intravisit::walk_crate(&mut pub_restricted_visitor, krate);
1840 pub_restricted_visitor.has_pub_restricted
1841 };
1842
1843 // Check for private types and traits in public interfaces.
1844 let mut visitor = PrivateItemsInPublicInterfacesVisitor {
1845 tcx,
1846 has_pub_restricted,
1847 old_error_set: &visitor.old_error_set,
1848 private_crates
1849 };
1850 krate.visit_all_item_likes(&mut DeepVisitor::new(&mut visitor));
1851 }
1852
1853 Lrc::new(visitor.access_levels)
1854 }
1855
1856 __build_diagnostic_array! { librustc_privacy, DIAGNOSTICS }