]> git.lizzy.rs Git - rust.git/blob - src/librustc_privacy/lib.rs
Rollup merge of #35558 - lukehinds:master, r=nikomatsakis
[rust.git] / src / librustc_privacy / lib.rs
1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 #![crate_name = "rustc_privacy"]
12 #![unstable(feature = "rustc_private", issue = "27812")]
13 #![crate_type = "dylib"]
14 #![crate_type = "rlib"]
15 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
16       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
17       html_root_url = "https://doc.rust-lang.org/nightly/")]
18 #![cfg_attr(not(stage0), deny(warnings))]
19
20 #![feature(rustc_diagnostic_macros)]
21 #![feature(rustc_private)]
22 #![feature(staged_api)]
23
24 extern crate rustc;
25 #[macro_use] extern crate syntax;
26 extern crate syntax_pos;
27
28 use rustc::dep_graph::DepNode;
29 use rustc::hir::{self, PatKind};
30 use rustc::hir::def::{self, Def};
31 use rustc::hir::def_id::DefId;
32 use rustc::hir::intravisit::{self, Visitor};
33 use rustc::hir::pat_util::EnumerateAndAdjustIterator;
34 use rustc::lint;
35 use rustc::middle::privacy::{AccessLevel, AccessLevels};
36 use rustc::ty::{self, TyCtxt};
37 use rustc::util::nodemap::NodeSet;
38 use syntax::ast;
39 use syntax_pos::Span;
40
41 use std::cmp;
42 use std::mem::replace;
43
44 pub mod diagnostics;
45
46 ////////////////////////////////////////////////////////////////////////////////
47 /// The embargo visitor, used to determine the exports of the ast
48 ////////////////////////////////////////////////////////////////////////////////
49
50 struct EmbargoVisitor<'a, 'tcx: 'a> {
51     tcx: TyCtxt<'a, 'tcx, 'tcx>,
52     export_map: &'a def::ExportMap,
53
54     // Accessibility levels for reachable nodes
55     access_levels: AccessLevels,
56     // Previous accessibility level, None means unreachable
57     prev_level: Option<AccessLevel>,
58     // Have something changed in the level map?
59     changed: bool,
60 }
61
62 struct ReachEverythingInTheInterfaceVisitor<'b, 'a: 'b, 'tcx: 'a> {
63     ev: &'b mut EmbargoVisitor<'a, 'tcx>,
64 }
65
66 impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
67     fn ty_level(&self, ty: &hir::Ty) -> Option<AccessLevel> {
68         if let hir::TyPath(..) = ty.node {
69             match self.tcx.expect_def(ty.id) {
70                 Def::PrimTy(..) | Def::SelfTy(..) | Def::TyParam(..) => {
71                     Some(AccessLevel::Public)
72                 }
73                 def => {
74                     if let Some(node_id) = self.tcx.map.as_local_node_id(def.def_id()) {
75                         self.get(node_id)
76                     } else {
77                         Some(AccessLevel::Public)
78                     }
79                 }
80             }
81         } else {
82             Some(AccessLevel::Public)
83         }
84     }
85
86     fn trait_level(&self, trait_ref: &hir::TraitRef) -> Option<AccessLevel> {
87         let did = self.tcx.expect_def(trait_ref.ref_id).def_id();
88         if let Some(node_id) = self.tcx.map.as_local_node_id(did) {
89             self.get(node_id)
90         } else {
91             Some(AccessLevel::Public)
92         }
93     }
94
95     fn get(&self, id: ast::NodeId) -> Option<AccessLevel> {
96         self.access_levels.map.get(&id).cloned()
97     }
98
99     // Updates node level and returns the updated level
100     fn update(&mut self, id: ast::NodeId, level: Option<AccessLevel>) -> Option<AccessLevel> {
101         let old_level = self.get(id);
102         // Accessibility levels can only grow
103         if level > old_level {
104             self.access_levels.map.insert(id, level.unwrap());
105             self.changed = true;
106             level
107         } else {
108             old_level
109         }
110     }
111
112     fn reach<'b>(&'b mut self) -> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
113         ReachEverythingInTheInterfaceVisitor { ev: self }
114     }
115 }
116
117 impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
118     /// We want to visit items in the context of their containing
119     /// module and so forth, so supply a crate for doing a deep walk.
120     fn visit_nested_item(&mut self, item: hir::ItemId) {
121         let tcx = self.tcx;
122         self.visit_item(tcx.map.expect_item(item.id))
123     }
124
125     fn visit_item(&mut self, item: &hir::Item) {
126         let inherited_item_level = match item.node {
127             // Impls inherit level from their types and traits
128             hir::ItemImpl(_, _, _, None, ref ty, _) => {
129                 self.ty_level(&ty)
130             }
131             hir::ItemImpl(_, _, _, Some(ref trait_ref), ref ty, _) => {
132                 cmp::min(self.ty_level(&ty), self.trait_level(trait_ref))
133             }
134             hir::ItemDefaultImpl(_, ref trait_ref) => {
135                 self.trait_level(trait_ref)
136             }
137             // Foreign mods inherit level from parents
138             hir::ItemForeignMod(..) => {
139                 self.prev_level
140             }
141             // Other `pub` items inherit levels from parents
142             _ => {
143                 if item.vis == hir::Public { self.prev_level } else { None }
144             }
145         };
146
147         // Update level of the item itself
148         let item_level = self.update(item.id, inherited_item_level);
149
150         // Update levels of nested things
151         match item.node {
152             hir::ItemEnum(ref def, _) => {
153                 for variant in &def.variants {
154                     let variant_level = self.update(variant.node.data.id(), item_level);
155                     for field in variant.node.data.fields() {
156                         self.update(field.id, variant_level);
157                     }
158                 }
159             }
160             hir::ItemImpl(_, _, _, None, _, ref impl_items) => {
161                 for impl_item in impl_items {
162                     if impl_item.vis == hir::Public {
163                         self.update(impl_item.id, item_level);
164                     }
165                 }
166             }
167             hir::ItemImpl(_, _, _, Some(_), _, ref impl_items) => {
168                 for impl_item in impl_items {
169                     self.update(impl_item.id, item_level);
170                 }
171             }
172             hir::ItemTrait(_, _, _, ref trait_items) => {
173                 for trait_item in trait_items {
174                     self.update(trait_item.id, item_level);
175                 }
176             }
177             hir::ItemStruct(ref def, _) => {
178                 if !def.is_struct() {
179                     self.update(def.id(), item_level);
180                 }
181                 for field in def.fields() {
182                     if field.vis == hir::Public {
183                         self.update(field.id, item_level);
184                     }
185                 }
186             }
187             hir::ItemForeignMod(ref foreign_mod) => {
188                 for foreign_item in &foreign_mod.items {
189                     if foreign_item.vis == hir::Public {
190                         self.update(foreign_item.id, item_level);
191                     }
192                 }
193             }
194             _ => {}
195         }
196
197         // Mark all items in interfaces of reachable items as reachable
198         match item.node {
199             // The interface is empty
200             hir::ItemExternCrate(..) => {}
201             // All nested items are checked by visit_item
202             hir::ItemMod(..) => {}
203             // Reexports are handled in visit_mod
204             hir::ItemUse(..) => {}
205             // Visit everything
206             hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) |
207             hir::ItemTrait(..) | hir::ItemTy(..) | hir::ItemImpl(_, _, _, Some(..), _, _) => {
208                 if item_level.is_some() {
209                     self.reach().visit_item(item);
210                 }
211             }
212             // Visit everything, but enum variants have their own levels
213             hir::ItemEnum(ref def, ref generics) => {
214                 if item_level.is_some() {
215                     self.reach().visit_generics(generics);
216                 }
217                 for variant in &def.variants {
218                     if self.get(variant.node.data.id()).is_some() {
219                         for field in variant.node.data.fields() {
220                             self.reach().visit_struct_field(field);
221                         }
222                         // Corner case: if the variant is reachable, but its
223                         // enum is not, make the enum reachable as well.
224                         self.update(item.id, Some(AccessLevel::Reachable));
225                     }
226                 }
227             }
228             // Visit everything, but foreign items have their own levels
229             hir::ItemForeignMod(ref foreign_mod) => {
230                 for foreign_item in &foreign_mod.items {
231                     if self.get(foreign_item.id).is_some() {
232                         self.reach().visit_foreign_item(foreign_item);
233                     }
234                 }
235             }
236             // Visit everything except for private fields
237             hir::ItemStruct(ref struct_def, ref generics) => {
238                 if item_level.is_some() {
239                     self.reach().visit_generics(generics);
240                     for field in struct_def.fields() {
241                         if self.get(field.id).is_some() {
242                             self.reach().visit_struct_field(field);
243                         }
244                     }
245                 }
246             }
247             // The interface is empty
248             hir::ItemDefaultImpl(..) => {}
249             // Visit everything except for private impl items
250             hir::ItemImpl(_, _, ref generics, None, _, ref impl_items) => {
251                 if item_level.is_some() {
252                     self.reach().visit_generics(generics);
253                     for impl_item in impl_items {
254                         if self.get(impl_item.id).is_some() {
255                             self.reach().visit_impl_item(impl_item);
256                         }
257                     }
258                 }
259             }
260         }
261
262         let orig_level = self.prev_level;
263         self.prev_level = item_level;
264
265         intravisit::walk_item(self, item);
266
267         self.prev_level = orig_level;
268     }
269
270     fn visit_block(&mut self, b: &'v hir::Block) {
271         let orig_level = replace(&mut self.prev_level, None);
272
273         // Blocks can have public items, for example impls, but they always
274         // start as completely private regardless of publicity of a function,
275         // constant, type, field, etc. in which this block resides
276         intravisit::walk_block(self, b);
277
278         self.prev_level = orig_level;
279     }
280
281     fn visit_mod(&mut self, m: &hir::Mod, _sp: Span, id: ast::NodeId) {
282         // This code is here instead of in visit_item so that the
283         // crate module gets processed as well.
284         if self.prev_level.is_some() {
285             if let Some(exports) = self.export_map.get(&id) {
286                 for export in exports {
287                     if let Some(node_id) = self.tcx.map.as_local_node_id(export.def_id) {
288                         self.update(node_id, Some(AccessLevel::Exported));
289                     }
290                 }
291             }
292         }
293
294         intravisit::walk_mod(self, m, id);
295     }
296
297     fn visit_macro_def(&mut self, md: &'v hir::MacroDef) {
298         self.update(md.id, Some(AccessLevel::Public));
299     }
300 }
301
302 impl<'b, 'a, 'tcx: 'a> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
303     // Make the type hidden under a type alias reachable
304     fn reach_aliased_type(&mut self, item: &hir::Item, path: &hir::Path) {
305         if let hir::ItemTy(ref ty, ref generics) = item.node {
306             // See `fn is_public_type_alias` for details
307             self.visit_ty(ty);
308             let provided_params = path.segments.last().unwrap().parameters.types().len();
309             for ty_param in &generics.ty_params[provided_params..] {
310                 if let Some(ref default_ty) = ty_param.default {
311                     self.visit_ty(default_ty);
312                 }
313             }
314         }
315     }
316 }
317
318 impl<'b, 'a, 'tcx: 'a, 'v> Visitor<'v> for ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
319     fn visit_ty(&mut self, ty: &hir::Ty) {
320         if let hir::TyPath(_, ref path) = ty.node {
321             let def = self.ev.tcx.expect_def(ty.id);
322             match def {
323                 Def::Struct(def_id) | Def::Enum(def_id) | Def::TyAlias(def_id) |
324                 Def::Trait(def_id) | Def::AssociatedTy(def_id, _) => {
325                     if let Some(node_id) = self.ev.tcx.map.as_local_node_id(def_id) {
326                         let item = self.ev.tcx.map.expect_item(node_id);
327                         if let Def::TyAlias(..) = def {
328                             // Type aliases are substituted. Associated type aliases are not
329                             // substituted yet, but ideally they should be.
330                             if self.ev.get(item.id).is_none() {
331                                 self.reach_aliased_type(item, path);
332                             }
333                         } else {
334                             self.ev.update(item.id, Some(AccessLevel::Reachable));
335                         }
336                     }
337                 }
338
339                 _ => {}
340             }
341         }
342
343         intravisit::walk_ty(self, ty);
344     }
345
346     fn visit_trait_ref(&mut self, trait_ref: &hir::TraitRef) {
347         let def_id = self.ev.tcx.expect_def(trait_ref.ref_id).def_id();
348         if let Some(node_id) = self.ev.tcx.map.as_local_node_id(def_id) {
349             let item = self.ev.tcx.map.expect_item(node_id);
350             self.ev.update(item.id, Some(AccessLevel::Reachable));
351         }
352
353         intravisit::walk_trait_ref(self, trait_ref);
354     }
355
356     // Don't recurse into function bodies
357     fn visit_block(&mut self, _: &hir::Block) {}
358     // Don't recurse into expressions in array sizes or const initializers
359     fn visit_expr(&mut self, _: &hir::Expr) {}
360     // Don't recurse into patterns in function arguments
361     fn visit_pat(&mut self, _: &hir::Pat) {}
362 }
363
364 ////////////////////////////////////////////////////////////////////////////////
365 /// The privacy visitor, where privacy checks take place (violations reported)
366 ////////////////////////////////////////////////////////////////////////////////
367
368 struct PrivacyVisitor<'a, 'tcx: 'a> {
369     tcx: TyCtxt<'a, 'tcx, 'tcx>,
370     curitem: ast::NodeId,
371     in_foreign: bool,
372 }
373
374 impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
375     fn item_is_accessible(&self, did: DefId) -> bool {
376         match self.tcx.map.as_local_node_id(did) {
377             Some(node_id) =>
378                 ty::Visibility::from_hir(&self.tcx.map.expect_item(node_id).vis, node_id, self.tcx),
379             None => self.tcx.sess.cstore.visibility(did),
380         }.is_accessible_from(self.curitem, &self.tcx.map)
381     }
382
383     // Checks that a field is in scope.
384     fn check_field(&mut self, span: Span, def: ty::AdtDef<'tcx>, field: ty::FieldDef<'tcx>) {
385         if def.adt_kind() == ty::AdtKind::Struct &&
386            !field.vis.is_accessible_from(self.curitem, &self.tcx.map) {
387             span_err!(self.tcx.sess, span, E0451, "field `{}` of struct `{}` is private",
388                       field.name, self.tcx.item_path_str(def.did));
389         }
390     }
391
392     // Checks that a method is in scope.
393     fn check_method(&mut self, span: Span, method_def_id: DefId) {
394         match self.tcx.impl_or_trait_item(method_def_id).container() {
395             // Trait methods are always all public. The only controlling factor
396             // is whether the trait itself is accessible or not.
397             ty::TraitContainer(trait_def_id) if !self.item_is_accessible(trait_def_id) => {
398                 let msg = format!("source trait `{}` is private",
399                                   self.tcx.item_path_str(trait_def_id));
400                 self.tcx.sess.span_err(span, &msg);
401             }
402             _ => {}
403         }
404     }
405 }
406
407 impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
408     /// We want to visit items in the context of their containing
409     /// module and so forth, so supply a crate for doing a deep walk.
410     fn visit_nested_item(&mut self, item: hir::ItemId) {
411         let tcx = self.tcx;
412         self.visit_item(tcx.map.expect_item(item.id))
413     }
414
415     fn visit_item(&mut self, item: &hir::Item) {
416         let orig_curitem = replace(&mut self.curitem, item.id);
417         intravisit::walk_item(self, item);
418         self.curitem = orig_curitem;
419     }
420
421     fn visit_expr(&mut self, expr: &hir::Expr) {
422         match expr.node {
423             hir::ExprMethodCall(..) => {
424                 let method_call = ty::MethodCall::expr(expr.id);
425                 let method = self.tcx.tables.borrow().method_map[&method_call];
426                 self.check_method(expr.span, method.def_id);
427             }
428             hir::ExprStruct(..) => {
429                 let adt = self.tcx.expr_ty(expr).ty_adt_def().unwrap();
430                 let variant = adt.variant_of_def(self.tcx.expect_def(expr.id));
431                 // RFC 736: ensure all unmentioned fields are visible.
432                 // Rather than computing the set of unmentioned fields
433                 // (i.e. `all_fields - fields`), just check them all.
434                 for field in &variant.fields {
435                     self.check_field(expr.span, adt, field);
436                 }
437             }
438             hir::ExprPath(..) => {
439                 if let Def::Struct(..) = self.tcx.expect_def(expr.id) {
440                     let expr_ty = self.tcx.expr_ty(expr);
441                     let def = match expr_ty.sty {
442                         ty::TyFnDef(_, _, &ty::BareFnTy { sig: ty::Binder(ty::FnSig {
443                             output: ty::FnConverging(ty), ..
444                         }), ..}) => ty,
445                         _ => expr_ty
446                     }.ty_adt_def().unwrap();
447                     let any_priv = def.struct_variant().fields.iter().any(|f| {
448                         !f.vis.is_accessible_from(self.curitem, &self.tcx.map)
449                     });
450                     if any_priv {
451                         span_err!(self.tcx.sess, expr.span, E0450,
452                                   "cannot invoke tuple struct constructor with private \
453                                    fields");
454                     }
455                 }
456             }
457             _ => {}
458         }
459
460         intravisit::walk_expr(self, expr);
461     }
462
463     fn visit_pat(&mut self, pattern: &hir::Pat) {
464         // Foreign functions do not have their patterns mapped in the def_map,
465         // and there's nothing really relevant there anyway, so don't bother
466         // checking privacy. If you can name the type then you can pass it to an
467         // external C function anyway.
468         if self.in_foreign { return }
469
470         match pattern.node {
471             PatKind::Struct(_, ref fields, _) => {
472                 let adt = self.tcx.pat_ty(pattern).ty_adt_def().unwrap();
473                 let variant = adt.variant_of_def(self.tcx.expect_def(pattern.id));
474                 for field in fields {
475                     self.check_field(pattern.span, adt, variant.field_named(field.node.name));
476                 }
477             }
478             PatKind::TupleStruct(_, ref fields, ddpos) => {
479                 match self.tcx.pat_ty(pattern).sty {
480                     ty::TyStruct(def, _) => {
481                         let expected_len = def.struct_variant().fields.len();
482                         for (i, field) in fields.iter().enumerate_and_adjust(expected_len, ddpos) {
483                             if let PatKind::Wild = field.node {
484                                 continue
485                             }
486                             self.check_field(field.span, def, &def.struct_variant().fields[i]);
487                         }
488                     }
489                     ty::TyEnum(..) => {
490                         // enum fields have no privacy at this time
491                     }
492                     _ => {}
493                 }
494             }
495             _ => {}
496         }
497
498         intravisit::walk_pat(self, pattern);
499     }
500
501     fn visit_foreign_item(&mut self, fi: &hir::ForeignItem) {
502         self.in_foreign = true;
503         intravisit::walk_foreign_item(self, fi);
504         self.in_foreign = false;
505     }
506 }
507
508 ///////////////////////////////////////////////////////////////////////////////
509 /// Obsolete visitors for checking for private items in public interfaces.
510 /// These visitors are supposed to be kept in frozen state and produce an
511 /// "old error node set". For backward compatibility the new visitor reports
512 /// warnings instead of hard errors when the erroneous node is not in this old set.
513 ///////////////////////////////////////////////////////////////////////////////
514
515 struct ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx: 'a> {
516     tcx: TyCtxt<'a, 'tcx, 'tcx>,
517     access_levels: &'a AccessLevels,
518     in_variant: bool,
519     // set of errors produced by this obsolete visitor
520     old_error_set: NodeSet,
521 }
522
523 struct ObsoleteCheckTypeForPrivatenessVisitor<'a, 'b: 'a, 'tcx: 'b> {
524     inner: &'a ObsoleteVisiblePrivateTypesVisitor<'b, 'tcx>,
525     /// whether the type refers to private types.
526     contains_private: bool,
527     /// whether we've recurred at all (i.e. if we're pointing at the
528     /// first type on which visit_ty was called).
529     at_outer_type: bool,
530     // whether that first type is a public path.
531     outer_type_is_public_path: bool,
532 }
533
534 impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
535     fn path_is_private_type(&self, path_id: ast::NodeId) -> bool {
536         let did = match self.tcx.expect_def(path_id) {
537             Def::PrimTy(..) | Def::SelfTy(..) => return false,
538             def => def.def_id(),
539         };
540
541         // A path can only be private if:
542         // it's in this crate...
543         if let Some(node_id) = self.tcx.map.as_local_node_id(did) {
544             // .. and it corresponds to a private type in the AST (this returns
545             // None for type parameters)
546             match self.tcx.map.find(node_id) {
547                 Some(hir::map::NodeItem(ref item)) => item.vis != hir::Public,
548                 Some(_) | None => false,
549             }
550         } else {
551             return false
552         }
553     }
554
555     fn trait_is_public(&self, trait_id: ast::NodeId) -> bool {
556         // FIXME: this would preferably be using `exported_items`, but all
557         // traits are exported currently (see `EmbargoVisitor.exported_trait`)
558         self.access_levels.is_public(trait_id)
559     }
560
561     fn check_ty_param_bound(&mut self,
562                             ty_param_bound: &hir::TyParamBound) {
563         if let hir::TraitTyParamBound(ref trait_ref, _) = *ty_param_bound {
564             if self.path_is_private_type(trait_ref.trait_ref.ref_id) {
565                 self.old_error_set.insert(trait_ref.trait_ref.ref_id);
566             }
567         }
568     }
569
570     fn item_is_public(&self, id: &ast::NodeId, vis: &hir::Visibility) -> bool {
571         self.access_levels.is_reachable(*id) || *vis == hir::Public
572     }
573 }
574
575 impl<'a, 'b, 'tcx, 'v> Visitor<'v> for ObsoleteCheckTypeForPrivatenessVisitor<'a, 'b, 'tcx> {
576     fn visit_ty(&mut self, ty: &hir::Ty) {
577         if let hir::TyPath(..) = ty.node {
578             if self.inner.path_is_private_type(ty.id) {
579                 self.contains_private = true;
580                 // found what we're looking for so let's stop
581                 // working.
582                 return
583             } else if self.at_outer_type {
584                 self.outer_type_is_public_path = true;
585             }
586         }
587         self.at_outer_type = false;
588         intravisit::walk_ty(self, ty)
589     }
590
591     // don't want to recurse into [, .. expr]
592     fn visit_expr(&mut self, _: &hir::Expr) {}
593 }
594
595 impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
596     /// We want to visit items in the context of their containing
597     /// module and so forth, so supply a crate for doing a deep walk.
598     fn visit_nested_item(&mut self, item: hir::ItemId) {
599         let tcx = self.tcx;
600         self.visit_item(tcx.map.expect_item(item.id))
601     }
602
603     fn visit_item(&mut self, item: &hir::Item) {
604         match item.node {
605             // contents of a private mod can be reexported, so we need
606             // to check internals.
607             hir::ItemMod(_) => {}
608
609             // An `extern {}` doesn't introduce a new privacy
610             // namespace (the contents have their own privacies).
611             hir::ItemForeignMod(_) => {}
612
613             hir::ItemTrait(_, _, ref bounds, _) => {
614                 if !self.trait_is_public(item.id) {
615                     return
616                 }
617
618                 for bound in bounds.iter() {
619                     self.check_ty_param_bound(bound)
620                 }
621             }
622
623             // impls need some special handling to try to offer useful
624             // error messages without (too many) false positives
625             // (i.e. we could just return here to not check them at
626             // all, or some worse estimation of whether an impl is
627             // publicly visible).
628             hir::ItemImpl(_, _, ref g, ref trait_ref, ref self_, ref impl_items) => {
629                 // `impl [... for] Private` is never visible.
630                 let self_contains_private;
631                 // impl [... for] Public<...>, but not `impl [... for]
632                 // Vec<Public>` or `(Public,)` etc.
633                 let self_is_public_path;
634
635                 // check the properties of the Self type:
636                 {
637                     let mut visitor = ObsoleteCheckTypeForPrivatenessVisitor {
638                         inner: self,
639                         contains_private: false,
640                         at_outer_type: true,
641                         outer_type_is_public_path: false,
642                     };
643                     visitor.visit_ty(&self_);
644                     self_contains_private = visitor.contains_private;
645                     self_is_public_path = visitor.outer_type_is_public_path;
646                 }
647
648                 // miscellaneous info about the impl
649
650                 // `true` iff this is `impl Private for ...`.
651                 let not_private_trait =
652                     trait_ref.as_ref().map_or(true, // no trait counts as public trait
653                                               |tr| {
654                         let did = self.tcx.expect_def(tr.ref_id).def_id();
655
656                         if let Some(node_id) = self.tcx.map.as_local_node_id(did) {
657                             self.trait_is_public(node_id)
658                         } else {
659                             true // external traits must be public
660                         }
661                     });
662
663                 // `true` iff this is a trait impl or at least one method is public.
664                 //
665                 // `impl Public { $( fn ...() {} )* }` is not visible.
666                 //
667                 // This is required over just using the methods' privacy
668                 // directly because we might have `impl<T: Foo<Private>> ...`,
669                 // and we shouldn't warn about the generics if all the methods
670                 // are private (because `T` won't be visible externally).
671                 let trait_or_some_public_method =
672                     trait_ref.is_some() ||
673                     impl_items.iter()
674                               .any(|impl_item| {
675                                   match impl_item.node {
676                                       hir::ImplItemKind::Const(..) |
677                                       hir::ImplItemKind::Method(..) => {
678                                           self.access_levels.is_reachable(impl_item.id)
679                                       }
680                                       hir::ImplItemKind::Type(_) => false,
681                                   }
682                               });
683
684                 if !self_contains_private &&
685                         not_private_trait &&
686                         trait_or_some_public_method {
687
688                     intravisit::walk_generics(self, g);
689
690                     match *trait_ref {
691                         None => {
692                             for impl_item in impl_items {
693                                 // This is where we choose whether to walk down
694                                 // further into the impl to check its items. We
695                                 // should only walk into public items so that we
696                                 // don't erroneously report errors for private
697                                 // types in private items.
698                                 match impl_item.node {
699                                     hir::ImplItemKind::Const(..) |
700                                     hir::ImplItemKind::Method(..)
701                                         if self.item_is_public(&impl_item.id, &impl_item.vis) =>
702                                     {
703                                         intravisit::walk_impl_item(self, impl_item)
704                                     }
705                                     hir::ImplItemKind::Type(..) => {
706                                         intravisit::walk_impl_item(self, impl_item)
707                                     }
708                                     _ => {}
709                                 }
710                             }
711                         }
712                         Some(ref tr) => {
713                             // Any private types in a trait impl fall into three
714                             // categories.
715                             // 1. mentioned in the trait definition
716                             // 2. mentioned in the type params/generics
717                             // 3. mentioned in the associated types of the impl
718                             //
719                             // Those in 1. can only occur if the trait is in
720                             // this crate and will've been warned about on the
721                             // trait definition (there's no need to warn twice
722                             // so we don't check the methods).
723                             //
724                             // Those in 2. are warned via walk_generics and this
725                             // call here.
726                             intravisit::walk_path(self, &tr.path);
727
728                             // Those in 3. are warned with this call.
729                             for impl_item in impl_items {
730                                 if let hir::ImplItemKind::Type(ref ty) = impl_item.node {
731                                     self.visit_ty(ty);
732                                 }
733                             }
734                         }
735                     }
736                 } else if trait_ref.is_none() && self_is_public_path {
737                     // impl Public<Private> { ... }. Any public static
738                     // methods will be visible as `Public::foo`.
739                     let mut found_pub_static = false;
740                     for impl_item in impl_items {
741                         match impl_item.node {
742                             hir::ImplItemKind::Const(..) => {
743                                 if self.item_is_public(&impl_item.id, &impl_item.vis) {
744                                     found_pub_static = true;
745                                     intravisit::walk_impl_item(self, impl_item);
746                                 }
747                             }
748                             hir::ImplItemKind::Method(ref sig, _) => {
749                                 if !sig.decl.has_self() &&
750                                         self.item_is_public(&impl_item.id, &impl_item.vis) {
751                                     found_pub_static = true;
752                                     intravisit::walk_impl_item(self, impl_item);
753                                 }
754                             }
755                             _ => {}
756                         }
757                     }
758                     if found_pub_static {
759                         intravisit::walk_generics(self, g)
760                     }
761                 }
762                 return
763             }
764
765             // `type ... = ...;` can contain private types, because
766             // we're introducing a new name.
767             hir::ItemTy(..) => return,
768
769             // not at all public, so we don't care
770             _ if !self.item_is_public(&item.id, &item.vis) => {
771                 return;
772             }
773
774             _ => {}
775         }
776
777         // We've carefully constructed it so that if we're here, then
778         // any `visit_ty`'s will be called on things that are in
779         // public signatures, i.e. things that we're interested in for
780         // this visitor.
781         intravisit::walk_item(self, item);
782     }
783
784     fn visit_generics(&mut self, generics: &hir::Generics) {
785         for ty_param in generics.ty_params.iter() {
786             for bound in ty_param.bounds.iter() {
787                 self.check_ty_param_bound(bound)
788             }
789         }
790         for predicate in &generics.where_clause.predicates {
791             match predicate {
792                 &hir::WherePredicate::BoundPredicate(ref bound_pred) => {
793                     for bound in bound_pred.bounds.iter() {
794                         self.check_ty_param_bound(bound)
795                     }
796                 }
797                 &hir::WherePredicate::RegionPredicate(_) => {}
798                 &hir::WherePredicate::EqPredicate(ref eq_pred) => {
799                     self.visit_ty(&eq_pred.ty);
800                 }
801             }
802         }
803     }
804
805     fn visit_foreign_item(&mut self, item: &hir::ForeignItem) {
806         if self.access_levels.is_reachable(item.id) {
807             intravisit::walk_foreign_item(self, item)
808         }
809     }
810
811     fn visit_ty(&mut self, t: &hir::Ty) {
812         if let hir::TyPath(..) = t.node {
813             if self.path_is_private_type(t.id) {
814                 self.old_error_set.insert(t.id);
815             }
816         }
817         intravisit::walk_ty(self, t)
818     }
819
820     fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics, item_id: ast::NodeId) {
821         if self.access_levels.is_reachable(v.node.data.id()) {
822             self.in_variant = true;
823             intravisit::walk_variant(self, v, g, item_id);
824             self.in_variant = false;
825         }
826     }
827
828     fn visit_struct_field(&mut self, s: &hir::StructField) {
829         if s.vis == hir::Public || self.in_variant {
830             intravisit::walk_struct_field(self, s);
831         }
832     }
833
834     // we don't need to introspect into these at all: an
835     // expression/block context can't possibly contain exported things.
836     // (Making them no-ops stops us from traversing the whole AST without
837     // having to be super careful about our `walk_...` calls above.)
838     // FIXME(#29524): Unfortunately this ^^^ is not true, blocks can contain
839     // exported items (e.g. impls) and actual code in rustc itself breaks
840     // if we don't traverse blocks in `EmbargoVisitor`
841     fn visit_block(&mut self, _: &hir::Block) {}
842     fn visit_expr(&mut self, _: &hir::Expr) {}
843 }
844
845 ///////////////////////////////////////////////////////////////////////////////
846 /// SearchInterfaceForPrivateItemsVisitor traverses an item's interface and
847 /// finds any private components in it.
848 /// PrivateItemsInPublicInterfacesVisitor ensures there are no private types
849 /// and traits in public interfaces.
850 ///////////////////////////////////////////////////////////////////////////////
851
852 struct SearchInterfaceForPrivateItemsVisitor<'a, 'tcx: 'a> {
853     tcx: TyCtxt<'a, 'tcx, 'tcx>,
854     /// The visitor checks that each component type is at least this visible
855     required_visibility: ty::Visibility,
856     /// The visibility of the least visible component that has been visited
857     min_visibility: ty::Visibility,
858     old_error_set: &'a NodeSet,
859 }
860
861 impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
862     fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, old_error_set: &'a NodeSet) -> Self {
863         SearchInterfaceForPrivateItemsVisitor {
864             tcx: tcx,
865             min_visibility: ty::Visibility::Public,
866             required_visibility: ty::Visibility::PrivateExternal,
867             old_error_set: old_error_set,
868         }
869     }
870 }
871
872 impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
873     // Return the visibility of the type alias's least visible component type when substituted
874     fn substituted_alias_visibility(&self, item: &hir::Item, path: &hir::Path)
875                                     -> Option<ty::Visibility> {
876         // Type alias is considered public if the aliased type is
877         // public, even if the type alias itself is private. So, something
878         // like `type A = u8; pub fn f() -> A {...}` doesn't cause an error.
879         if let hir::ItemTy(ref ty, ref generics) = item.node {
880             let mut check = SearchInterfaceForPrivateItemsVisitor::new(self.tcx,
881                                                                        self.old_error_set);
882             check.visit_ty(ty);
883             // If a private type alias with default type parameters is used in public
884             // interface we must ensure, that the defaults are public if they are actually used.
885             // ```
886             // type Alias<T = Private> = T;
887             // pub fn f() -> Alias {...} // `Private` is implicitly used here, so it must be public
888             // ```
889             let provided_params = path.segments.last().unwrap().parameters.types().len();
890             for ty_param in &generics.ty_params[provided_params..] {
891                 if let Some(ref default_ty) = ty_param.default {
892                     check.visit_ty(default_ty);
893                 }
894             }
895             Some(check.min_visibility)
896         } else {
897             None
898         }
899     }
900 }
901
902 impl<'a, 'tcx: 'a, 'v> Visitor<'v> for SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
903     fn visit_ty(&mut self, ty: &hir::Ty) {
904         if let hir::TyPath(_, ref path) = ty.node {
905             match self.tcx.expect_def(ty.id) {
906                 Def::PrimTy(..) | Def::SelfTy(..) | Def::TyParam(..) => {
907                     // Public
908                 }
909                 Def::AssociatedTy(..)
910                     if self.required_visibility == ty::Visibility::PrivateExternal => {
911                     // Conservatively approximate the whole type alias as public without
912                     // recursing into its components when determining impl publicity.
913                     // For example, `impl <Type as Trait>::Alias {...}` may be a public impl
914                     // even if both `Type` and `Trait` are private.
915                     // Ideally, associated types should be substituted in the same way as
916                     // free type aliases, but this isn't done yet.
917                     return
918                 }
919                 Def::Struct(def_id) | Def::Enum(def_id) | Def::TyAlias(def_id) |
920                 Def::Trait(def_id) | Def::AssociatedTy(def_id, _) => {
921                     // Non-local means public (private items can't leave their crate, modulo bugs)
922                     if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
923                         let item = self.tcx.map.expect_item(node_id);
924                         let vis = match self.substituted_alias_visibility(item, path) {
925                             Some(vis) => vis,
926                             None => ty::Visibility::from_hir(&item.vis, node_id, self.tcx),
927                         };
928
929                         if !vis.is_at_least(self.min_visibility, &self.tcx.map) {
930                             self.min_visibility = vis;
931                         }
932                         if !vis.is_at_least(self.required_visibility, &self.tcx.map) {
933                             if self.tcx.sess.features.borrow().pub_restricted ||
934                                self.old_error_set.contains(&ty.id) {
935                                 span_err!(self.tcx.sess, ty.span, E0446,
936                                           "private type in public interface");
937                             } else {
938                                 self.tcx.sess.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
939                                                        node_id,
940                                                        ty.span,
941                                                        format!("private type in public \
942                                                                 interface (error E0446)"));
943                             }
944                         }
945                     }
946                 }
947                 _ => {}
948             }
949         }
950
951         intravisit::walk_ty(self, ty);
952     }
953
954     fn visit_trait_ref(&mut self, trait_ref: &hir::TraitRef) {
955         // Non-local means public (private items can't leave their crate, modulo bugs)
956         let def_id = self.tcx.expect_def(trait_ref.ref_id).def_id();
957         if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
958             let item = self.tcx.map.expect_item(node_id);
959             let vis = ty::Visibility::from_hir(&item.vis, node_id, self.tcx);
960
961             if !vis.is_at_least(self.min_visibility, &self.tcx.map) {
962                 self.min_visibility = vis;
963             }
964             if !vis.is_at_least(self.required_visibility, &self.tcx.map) {
965                 if self.tcx.sess.features.borrow().pub_restricted ||
966                    self.old_error_set.contains(&trait_ref.ref_id) {
967                     span_err!(self.tcx.sess, trait_ref.path.span, E0445,
968                               "private trait in public interface");
969                 } else {
970                     self.tcx.sess.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
971                                            node_id,
972                                            trait_ref.path.span,
973                                            "private trait in public interface (error E0445)"
974                                                 .to_string());
975                 }
976             }
977         }
978
979         intravisit::walk_trait_ref(self, trait_ref);
980     }
981
982     // Don't recurse into function bodies
983     fn visit_block(&mut self, _: &hir::Block) {}
984     // Don't recurse into expressions in array sizes or const initializers
985     fn visit_expr(&mut self, _: &hir::Expr) {}
986     // Don't recurse into patterns in function arguments
987     fn visit_pat(&mut self, _: &hir::Pat) {}
988 }
989
990 struct PrivateItemsInPublicInterfacesVisitor<'a, 'tcx: 'a> {
991     tcx: TyCtxt<'a, 'tcx, 'tcx>,
992     old_error_set: &'a NodeSet,
993 }
994
995 impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
996     // A type is considered public if it doesn't contain any private components
997     fn ty_visibility(&self, ty: &hir::Ty) -> ty::Visibility {
998         let mut check = SearchInterfaceForPrivateItemsVisitor::new(self.tcx, self.old_error_set);
999         check.visit_ty(ty);
1000         check.min_visibility
1001     }
1002
1003     // A trait reference is considered public if it doesn't contain any private components
1004     fn trait_ref_visibility(&self, trait_ref: &hir::TraitRef) -> ty::Visibility {
1005         let mut check = SearchInterfaceForPrivateItemsVisitor::new(self.tcx, self.old_error_set);
1006         check.visit_trait_ref(trait_ref);
1007         check.min_visibility
1008     }
1009 }
1010
1011 impl<'a, 'tcx, 'v> Visitor<'v> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
1012     fn visit_item(&mut self, item: &hir::Item) {
1013         let min = |vis1: ty::Visibility, vis2| {
1014             if vis1.is_at_least(vis2, &self.tcx.map) { vis2 } else { vis1 }
1015         };
1016
1017         let mut check = SearchInterfaceForPrivateItemsVisitor::new(self.tcx, self.old_error_set);
1018         let item_visibility = ty::Visibility::from_hir(&item.vis, item.id, self.tcx);
1019
1020         match item.node {
1021             // Crates are always public
1022             hir::ItemExternCrate(..) => {}
1023             // All nested items are checked by visit_item
1024             hir::ItemMod(..) => {}
1025             // Checked in resolve
1026             hir::ItemUse(..) => {}
1027             // Subitems of these items have inherited publicity
1028             hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) |
1029             hir::ItemEnum(..) | hir::ItemTrait(..) | hir::ItemTy(..) => {
1030                 check.required_visibility = item_visibility;
1031                 check.visit_item(item);
1032             }
1033             // Subitems of foreign modules have their own publicity
1034             hir::ItemForeignMod(ref foreign_mod) => {
1035                 for foreign_item in &foreign_mod.items {
1036                     check.required_visibility =
1037                         ty::Visibility::from_hir(&foreign_item.vis, item.id, self.tcx);
1038                     check.visit_foreign_item(foreign_item);
1039                 }
1040             }
1041             // Subitems of structs have their own publicity
1042             hir::ItemStruct(ref struct_def, ref generics) => {
1043                 check.required_visibility = item_visibility;
1044                 check.visit_generics(generics);
1045
1046                 for field in struct_def.fields() {
1047                     let field_visibility = ty::Visibility::from_hir(&field.vis, item.id, self.tcx);
1048                     check.required_visibility = min(item_visibility, field_visibility);
1049                     check.visit_struct_field(field);
1050                 }
1051             }
1052             // The interface is empty
1053             hir::ItemDefaultImpl(..) => {}
1054             // An inherent impl is public when its type is public
1055             // Subitems of inherent impls have their own publicity
1056             hir::ItemImpl(_, _, ref generics, None, ref ty, ref impl_items) => {
1057                 let ty_vis = self.ty_visibility(ty);
1058                 check.required_visibility = ty_vis;
1059                 check.visit_generics(generics);
1060
1061                 for impl_item in impl_items {
1062                     let impl_item_vis =
1063                         ty::Visibility::from_hir(&impl_item.vis, item.id, self.tcx);
1064                     check.required_visibility = min(impl_item_vis, ty_vis);
1065                     check.visit_impl_item(impl_item);
1066                 }
1067             }
1068             // A trait impl is public when both its type and its trait are public
1069             // Subitems of trait impls have inherited publicity
1070             hir::ItemImpl(_, _, ref generics, Some(ref trait_ref), ref ty, ref impl_items) => {
1071                 let vis = min(self.ty_visibility(ty), self.trait_ref_visibility(trait_ref));
1072                 check.required_visibility = vis;
1073                 check.visit_generics(generics);
1074                 for impl_item in impl_items {
1075                     check.visit_impl_item(impl_item);
1076                 }
1077             }
1078         }
1079     }
1080 }
1081
1082 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
1083                              export_map: &def::ExportMap)
1084                              -> AccessLevels {
1085     let _task = tcx.dep_graph.in_task(DepNode::Privacy);
1086
1087     let krate = tcx.map.krate();
1088
1089     // Use the parent map to check the privacy of everything
1090     let mut visitor = PrivacyVisitor {
1091         curitem: ast::DUMMY_NODE_ID,
1092         in_foreign: false,
1093         tcx: tcx,
1094     };
1095     intravisit::walk_crate(&mut visitor, krate);
1096
1097     tcx.sess.abort_if_errors();
1098
1099     // Build up a set of all exported items in the AST. This is a set of all
1100     // items which are reachable from external crates based on visibility.
1101     let mut visitor = EmbargoVisitor {
1102         tcx: tcx,
1103         export_map: export_map,
1104         access_levels: Default::default(),
1105         prev_level: Some(AccessLevel::Public),
1106         changed: false,
1107     };
1108     loop {
1109         intravisit::walk_crate(&mut visitor, krate);
1110         if visitor.changed {
1111             visitor.changed = false;
1112         } else {
1113             break
1114         }
1115     }
1116     visitor.update(ast::CRATE_NODE_ID, Some(AccessLevel::Public));
1117
1118     {
1119         let mut visitor = ObsoleteVisiblePrivateTypesVisitor {
1120             tcx: tcx,
1121             access_levels: &visitor.access_levels,
1122             in_variant: false,
1123             old_error_set: NodeSet(),
1124         };
1125         intravisit::walk_crate(&mut visitor, krate);
1126
1127         // Check for private types and traits in public interfaces
1128         let mut visitor = PrivateItemsInPublicInterfacesVisitor {
1129             tcx: tcx,
1130             old_error_set: &visitor.old_error_set,
1131         };
1132         krate.visit_all_items(&mut visitor);
1133     }
1134
1135     visitor.access_levels
1136 }
1137
1138 __build_diagnostic_array! { librustc_privacy, DIAGNOSTICS }