]> git.lizzy.rs Git - rust.git/blob - src/librustc_privacy/lib.rs
Rollup merge of #31989 - Kimundi:more_flexible_str_pattern_indirection, r=bluss
[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 #[macro_use] extern crate log;
25 #[macro_use] extern crate syntax;
26
27 extern crate rustc;
28 extern crate rustc_front;
29
30 use self::PrivacyResult::*;
31 use self::FieldName::*;
32
33 use std::cmp;
34 use std::mem::replace;
35
36 use rustc_front::hir::{self, PatKind};
37 use rustc_front::intravisit::{self, Visitor};
38
39 use rustc::dep_graph::DepNode;
40 use rustc::lint;
41 use rustc::middle::def::{self, Def};
42 use rustc::middle::def_id::DefId;
43 use rustc::middle::privacy::{AccessLevel, AccessLevels};
44 use rustc::middle::privacy::ImportUse::*;
45 use rustc::middle::privacy::LastPrivate::*;
46 use rustc::middle::privacy::PrivateDep::*;
47 use rustc::middle::privacy::ExternalExports;
48 use rustc::middle::ty;
49 use rustc::util::nodemap::{NodeMap, NodeSet};
50 use rustc::front::map as ast_map;
51
52 use syntax::ast;
53 use syntax::codemap::Span;
54
55 pub mod diagnostics;
56
57 type Context<'a, 'tcx> = (&'a ty::MethodMap<'tcx>, &'a def::ExportMap);
58
59 /// Result of a checking operation - None => no errors were found. Some => an
60 /// error and contains the span and message for reporting that error and
61 /// optionally the same for a note about the error.
62 type CheckResult = Option<(Span, String, Option<(Span, String)>)>;
63
64 ////////////////////////////////////////////////////////////////////////////////
65 /// The parent visitor, used to determine what's the parent of what (node-wise)
66 ////////////////////////////////////////////////////////////////////////////////
67
68 struct ParentVisitor<'a, 'tcx:'a> {
69     tcx: &'a ty::ctxt<'tcx>,
70     parents: NodeMap<ast::NodeId>,
71     curparent: ast::NodeId,
72 }
73
74 impl<'a, 'tcx, 'v> Visitor<'v> for ParentVisitor<'a, 'tcx> {
75     /// We want to visit items in the context of their containing
76     /// module and so forth, so supply a crate for doing a deep walk.
77     fn visit_nested_item(&mut self, item: hir::ItemId) {
78         self.visit_item(self.tcx.map.expect_item(item.id))
79     }
80     fn visit_item(&mut self, item: &hir::Item) {
81         self.parents.insert(item.id, self.curparent);
82
83         let prev = self.curparent;
84         match item.node {
85             hir::ItemMod(..) => { self.curparent = item.id; }
86             // Enum variants are parented to the enum definition itself because
87             // they inherit privacy
88             hir::ItemEnum(ref def, _) => {
89                 for variant in &def.variants {
90                     // The parent is considered the enclosing enum because the
91                     // enum will dictate the privacy visibility of this variant
92                     // instead.
93                     self.parents.insert(variant.node.data.id(), item.id);
94                 }
95             }
96
97             // Trait methods are always considered "public", but if the trait is
98             // private then we need some private item in the chain from the
99             // method to the root. In this case, if the trait is private, then
100             // parent all the methods to the trait to indicate that they're
101             // private.
102             hir::ItemTrait(_, _, _, ref trait_items) if item.vis != hir::Public => {
103                 for trait_item in trait_items {
104                     self.parents.insert(trait_item.id, item.id);
105                 }
106             }
107
108             _ => {}
109         }
110         intravisit::walk_item(self, item);
111         self.curparent = prev;
112     }
113
114     fn visit_foreign_item(&mut self, a: &hir::ForeignItem) {
115         self.parents.insert(a.id, self.curparent);
116         intravisit::walk_foreign_item(self, a);
117     }
118
119     fn visit_fn(&mut self, a: intravisit::FnKind<'v>, b: &'v hir::FnDecl,
120                 c: &'v hir::Block, d: Span, id: ast::NodeId) {
121         // We already took care of some trait methods above, otherwise things
122         // like impl methods and pub trait methods are parented to the
123         // containing module, not the containing trait.
124         if !self.parents.contains_key(&id) {
125             self.parents.insert(id, self.curparent);
126         }
127         intravisit::walk_fn(self, a, b, c, d);
128     }
129
130     fn visit_impl_item(&mut self, ii: &'v hir::ImplItem) {
131         // visit_fn handles methods, but associated consts have to be handled
132         // here.
133         if !self.parents.contains_key(&ii.id) {
134             self.parents.insert(ii.id, self.curparent);
135         }
136         intravisit::walk_impl_item(self, ii);
137     }
138
139     fn visit_variant_data(&mut self, s: &hir::VariantData, _: ast::Name,
140                         _: &'v hir::Generics, item_id: ast::NodeId, _: Span) {
141         // Struct constructors are parented to their struct definitions because
142         // they essentially are the struct definitions.
143         if !s.is_struct() {
144             self.parents.insert(s.id(), item_id);
145         }
146
147         // While we have the id of the struct definition, go ahead and parent
148         // all the fields.
149         for field in s.fields() {
150             self.parents.insert(field.node.id, self.curparent);
151         }
152         intravisit::walk_struct_def(self, s)
153     }
154 }
155
156 ////////////////////////////////////////////////////////////////////////////////
157 /// The embargo visitor, used to determine the exports of the ast
158 ////////////////////////////////////////////////////////////////////////////////
159
160 struct EmbargoVisitor<'a, 'tcx: 'a> {
161     tcx: &'a ty::ctxt<'tcx>,
162     export_map: &'a def::ExportMap,
163
164     // Accessibility levels for reachable nodes
165     access_levels: AccessLevels,
166     // Previous accessibility level, None means unreachable
167     prev_level: Option<AccessLevel>,
168     // Have something changed in the level map?
169     changed: bool,
170 }
171
172 struct ReachEverythingInTheInterfaceVisitor<'b, 'a: 'b, 'tcx: 'a> {
173     ev: &'b mut EmbargoVisitor<'a, 'tcx>,
174 }
175
176 impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
177     fn ty_level(&self, ty: &hir::Ty) -> Option<AccessLevel> {
178         if let hir::TyPath(..) = ty.node {
179             match self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def() {
180                 Def::PrimTy(..) | Def::SelfTy(..) | Def::TyParam(..) => {
181                     Some(AccessLevel::Public)
182                 }
183                 def => {
184                     if let Some(node_id) = self.tcx.map.as_local_node_id(def.def_id()) {
185                         self.get(node_id)
186                     } else {
187                         Some(AccessLevel::Public)
188                     }
189                 }
190             }
191         } else {
192             Some(AccessLevel::Public)
193         }
194     }
195
196     fn trait_level(&self, trait_ref: &hir::TraitRef) -> Option<AccessLevel> {
197         let did = self.tcx.trait_ref_to_def_id(trait_ref);
198         if let Some(node_id) = self.tcx.map.as_local_node_id(did) {
199             self.get(node_id)
200         } else {
201             Some(AccessLevel::Public)
202         }
203     }
204
205     fn get(&self, id: ast::NodeId) -> Option<AccessLevel> {
206         self.access_levels.map.get(&id).cloned()
207     }
208
209     // Updates node level and returns the updated level
210     fn update(&mut self, id: ast::NodeId, level: Option<AccessLevel>) -> Option<AccessLevel> {
211         let old_level = self.get(id);
212         // Accessibility levels can only grow
213         if level > old_level {
214             self.access_levels.map.insert(id, level.unwrap());
215             self.changed = true;
216             level
217         } else {
218             old_level
219         }
220     }
221
222     fn reach<'b>(&'b mut self) -> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
223         ReachEverythingInTheInterfaceVisitor { ev: self }
224     }
225 }
226
227 impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
228     /// We want to visit items in the context of their containing
229     /// module and so forth, so supply a crate for doing a deep walk.
230     fn visit_nested_item(&mut self, item: hir::ItemId) {
231         self.visit_item(self.tcx.map.expect_item(item.id))
232     }
233
234     fn visit_item(&mut self, item: &hir::Item) {
235         let inherited_item_level = match item.node {
236             // Impls inherit level from their types and traits
237             hir::ItemImpl(_, _, _, None, ref ty, _) => {
238                 self.ty_level(&ty)
239             }
240             hir::ItemImpl(_, _, _, Some(ref trait_ref), ref ty, _) => {
241                 cmp::min(self.ty_level(&ty), self.trait_level(trait_ref))
242             }
243             hir::ItemDefaultImpl(_, ref trait_ref) => {
244                 self.trait_level(trait_ref)
245             }
246             // Foreign mods inherit level from parents
247             hir::ItemForeignMod(..) => {
248                 self.prev_level
249             }
250             // Other `pub` items inherit levels from parents
251             _ => {
252                 if item.vis == hir::Public { self.prev_level } else { None }
253             }
254         };
255
256         // Update level of the item itself
257         let item_level = self.update(item.id, inherited_item_level);
258
259         // Update levels of nested things
260         match item.node {
261             hir::ItemEnum(ref def, _) => {
262                 for variant in &def.variants {
263                     let variant_level = self.update(variant.node.data.id(), item_level);
264                     for field in variant.node.data.fields() {
265                         self.update(field.node.id, variant_level);
266                     }
267                 }
268             }
269             hir::ItemImpl(_, _, _, None, _, ref impl_items) => {
270                 for impl_item in impl_items {
271                     if impl_item.vis == hir::Public {
272                         self.update(impl_item.id, item_level);
273                     }
274                 }
275             }
276             hir::ItemImpl(_, _, _, Some(_), _, ref impl_items) => {
277                 for impl_item in impl_items {
278                     self.update(impl_item.id, item_level);
279                 }
280             }
281             hir::ItemTrait(_, _, _, ref trait_items) => {
282                 for trait_item in trait_items {
283                     self.update(trait_item.id, item_level);
284                 }
285             }
286             hir::ItemStruct(ref def, _) => {
287                 if !def.is_struct() {
288                     self.update(def.id(), item_level);
289                 }
290                 for field in def.fields() {
291                     if field.node.kind.visibility() == hir::Public {
292                         self.update(field.node.id, item_level);
293                     }
294                 }
295             }
296             hir::ItemForeignMod(ref foreign_mod) => {
297                 for foreign_item in &foreign_mod.items {
298                     if foreign_item.vis == hir::Public {
299                         self.update(foreign_item.id, item_level);
300                     }
301                 }
302             }
303             _ => {}
304         }
305
306         // Mark all items in interfaces of reachable items as reachable
307         match item.node {
308             // The interface is empty
309             hir::ItemExternCrate(..) => {}
310             // All nested items are checked by visit_item
311             hir::ItemMod(..) => {}
312             // Reexports are handled in visit_mod
313             hir::ItemUse(..) => {}
314             // Visit everything
315             hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) |
316             hir::ItemTrait(..) | hir::ItemTy(..) | hir::ItemImpl(_, _, _, Some(..), _, _) => {
317                 if item_level.is_some() {
318                     self.reach().visit_item(item);
319                 }
320             }
321             // Visit everything, but enum variants have their own levels
322             hir::ItemEnum(ref def, ref generics) => {
323                 if item_level.is_some() {
324                     self.reach().visit_generics(generics);
325                 }
326                 for variant in &def.variants {
327                     if self.get(variant.node.data.id()).is_some() {
328                         for field in variant.node.data.fields() {
329                             self.reach().visit_struct_field(field);
330                         }
331                         // Corner case: if the variant is reachable, but its
332                         // enum is not, make the enum reachable as well.
333                         self.update(item.id, Some(AccessLevel::Reachable));
334                     }
335                 }
336             }
337             // Visit everything, but foreign items have their own levels
338             hir::ItemForeignMod(ref foreign_mod) => {
339                 for foreign_item in &foreign_mod.items {
340                     if self.get(foreign_item.id).is_some() {
341                         self.reach().visit_foreign_item(foreign_item);
342                     }
343                 }
344             }
345             // Visit everything except for private fields
346             hir::ItemStruct(ref struct_def, ref generics) => {
347                 if item_level.is_some() {
348                     self.reach().visit_generics(generics);
349                     for field in struct_def.fields() {
350                         if self.get(field.node.id).is_some() {
351                             self.reach().visit_struct_field(field);
352                         }
353                     }
354                 }
355             }
356             // The interface is empty
357             hir::ItemDefaultImpl(..) => {}
358             // Visit everything except for private impl items
359             hir::ItemImpl(_, _, ref generics, None, _, ref impl_items) => {
360                 if item_level.is_some() {
361                     self.reach().visit_generics(generics);
362                     for impl_item in impl_items {
363                         if self.get(impl_item.id).is_some() {
364                             self.reach().visit_impl_item(impl_item);
365                         }
366                     }
367                 }
368             }
369         }
370
371         let orig_level = self.prev_level;
372         self.prev_level = item_level;
373
374         intravisit::walk_item(self, item);
375
376         self.prev_level = orig_level;
377     }
378
379     fn visit_block(&mut self, b: &'v hir::Block) {
380         let orig_level = replace(&mut self.prev_level, None);
381
382         // Blocks can have public items, for example impls, but they always
383         // start as completely private regardless of publicity of a function,
384         // constant, type, field, etc. in which this block resides
385         intravisit::walk_block(self, b);
386
387         self.prev_level = orig_level;
388     }
389
390     fn visit_mod(&mut self, m: &hir::Mod, _sp: Span, id: ast::NodeId) {
391         // This code is here instead of in visit_item so that the
392         // crate module gets processed as well.
393         if self.prev_level.is_some() {
394             if let Some(exports) = self.export_map.get(&id) {
395                 for export in exports {
396                     if let Some(node_id) = self.tcx.map.as_local_node_id(export.def_id) {
397                         self.update(node_id, Some(AccessLevel::Exported));
398                     }
399                 }
400             }
401         }
402
403         intravisit::walk_mod(self, m);
404     }
405
406     fn visit_macro_def(&mut self, md: &'v hir::MacroDef) {
407         self.update(md.id, Some(AccessLevel::Public));
408     }
409 }
410
411 impl<'b, 'a, 'tcx: 'a> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
412     // Make the type hidden under a type alias reachable
413     fn reach_aliased_type(&mut self, item: &hir::Item, path: &hir::Path) {
414         if let hir::ItemTy(ref ty, ref generics) = item.node {
415             // See `fn is_public_type_alias` for details
416             self.visit_ty(ty);
417             let provided_params = path.segments.last().unwrap().parameters.types().len();
418             for ty_param in &generics.ty_params[provided_params..] {
419                 if let Some(ref default_ty) = ty_param.default {
420                     self.visit_ty(default_ty);
421                 }
422             }
423         }
424     }
425 }
426
427 impl<'b, 'a, 'tcx: 'a, 'v> Visitor<'v> for ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
428     fn visit_ty(&mut self, ty: &hir::Ty) {
429         if let hir::TyPath(_, ref path) = ty.node {
430             let def = self.ev.tcx.def_map.borrow().get(&ty.id).unwrap().full_def();
431             match def {
432                 Def::Struct(def_id) | Def::Enum(def_id) | Def::TyAlias(def_id) |
433                 Def::Trait(def_id) | Def::AssociatedTy(def_id, _) => {
434                     if let Some(node_id) = self.ev.tcx.map.as_local_node_id(def_id) {
435                         let item = self.ev.tcx.map.expect_item(node_id);
436                         if let Def::TyAlias(..) = def {
437                             // Type aliases are substituted. Associated type aliases are not
438                             // substituted yet, but ideally they should be.
439                             if self.ev.get(item.id).is_none() {
440                                 self.reach_aliased_type(item, path);
441                             }
442                         } else {
443                             self.ev.update(item.id, Some(AccessLevel::Reachable));
444                         }
445                     }
446                 }
447
448                 _ => {}
449             }
450         }
451
452         intravisit::walk_ty(self, ty);
453     }
454
455     fn visit_trait_ref(&mut self, trait_ref: &hir::TraitRef) {
456         let def_id = self.ev.tcx.trait_ref_to_def_id(trait_ref);
457         if let Some(node_id) = self.ev.tcx.map.as_local_node_id(def_id) {
458             let item = self.ev.tcx.map.expect_item(node_id);
459             self.ev.update(item.id, Some(AccessLevel::Reachable));
460         }
461
462         intravisit::walk_trait_ref(self, trait_ref);
463     }
464
465     // Don't recurse into function bodies
466     fn visit_block(&mut self, _: &hir::Block) {}
467     // Don't recurse into expressions in array sizes or const initializers
468     fn visit_expr(&mut self, _: &hir::Expr) {}
469     // Don't recurse into patterns in function arguments
470     fn visit_pat(&mut self, _: &hir::Pat) {}
471 }
472
473 ////////////////////////////////////////////////////////////////////////////////
474 /// The privacy visitor, where privacy checks take place (violations reported)
475 ////////////////////////////////////////////////////////////////////////////////
476
477 struct PrivacyVisitor<'a, 'tcx: 'a> {
478     tcx: &'a ty::ctxt<'tcx>,
479     curitem: ast::NodeId,
480     in_foreign: bool,
481     parents: NodeMap<ast::NodeId>,
482     external_exports: ExternalExports,
483 }
484
485 #[derive(Debug)]
486 enum PrivacyResult {
487     Allowable,
488     ExternallyDenied,
489     DisallowedBy(ast::NodeId),
490 }
491
492 enum FieldName {
493     UnnamedField(usize), // index
494     NamedField(ast::Name),
495 }
496
497 impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
498     // used when debugging
499     fn nodestr(&self, id: ast::NodeId) -> String {
500         self.tcx.map.node_to_string(id).to_string()
501     }
502
503     // Determines whether the given definition is public from the point of view
504     // of the current item.
505     fn def_privacy(&self, did: DefId) -> PrivacyResult {
506         let node_id = if let Some(node_id) = self.tcx.map.as_local_node_id(did) {
507             node_id
508         } else {
509             if self.external_exports.contains(&did) {
510                 debug!("privacy - {:?} was externally exported", did);
511                 return Allowable;
512             }
513             debug!("privacy - is {:?} a public method", did);
514
515             return match self.tcx.impl_or_trait_items.borrow().get(&did) {
516                 Some(&ty::ConstTraitItem(ref ac)) => {
517                     debug!("privacy - it's a const: {:?}", *ac);
518                     match ac.container {
519                         ty::TraitContainer(id) => {
520                             debug!("privacy - recursing on trait {:?}", id);
521                             self.def_privacy(id)
522                         }
523                         ty::ImplContainer(id) => {
524                             match self.tcx.impl_trait_ref(id) {
525                                 Some(t) => {
526                                     debug!("privacy - impl of trait {:?}", id);
527                                     self.def_privacy(t.def_id)
528                                 }
529                                 None => {
530                                     debug!("privacy - found inherent \
531                                             associated constant {:?}",
532                                             ac.vis);
533                                     if ac.vis == hir::Public {
534                                         Allowable
535                                     } else {
536                                         ExternallyDenied
537                                     }
538                                 }
539                             }
540                         }
541                     }
542                 }
543                 Some(&ty::MethodTraitItem(ref meth)) => {
544                     debug!("privacy - well at least it's a method: {:?}",
545                            *meth);
546                     match meth.container {
547                         ty::TraitContainer(id) => {
548                             debug!("privacy - recursing on trait {:?}", id);
549                             self.def_privacy(id)
550                         }
551                         ty::ImplContainer(id) => {
552                             match self.tcx.impl_trait_ref(id) {
553                                 Some(t) => {
554                                     debug!("privacy - impl of trait {:?}", id);
555                                     self.def_privacy(t.def_id)
556                                 }
557                                 None => {
558                                     debug!("privacy - found a method {:?}",
559                                             meth.vis);
560                                     if meth.vis == hir::Public {
561                                         Allowable
562                                     } else {
563                                         ExternallyDenied
564                                     }
565                                 }
566                             }
567                         }
568                     }
569                 }
570                 Some(&ty::TypeTraitItem(ref typedef)) => {
571                     match typedef.container {
572                         ty::TraitContainer(id) => {
573                             debug!("privacy - recursing on trait {:?}", id);
574                             self.def_privacy(id)
575                         }
576                         ty::ImplContainer(id) => {
577                             match self.tcx.impl_trait_ref(id) {
578                                 Some(t) => {
579                                     debug!("privacy - impl of trait {:?}", id);
580                                     self.def_privacy(t.def_id)
581                                 }
582                                 None => {
583                                     debug!("privacy - found a typedef {:?}",
584                                             typedef.vis);
585                                     if typedef.vis == hir::Public {
586                                         Allowable
587                                     } else {
588                                         ExternallyDenied
589                                     }
590                                 }
591                             }
592                         }
593                     }
594                 }
595                 None => {
596                     debug!("privacy - nope, not even a method");
597                     ExternallyDenied
598                 }
599             };
600         };
601
602         debug!("privacy - local {} not public all the way down",
603                self.tcx.map.node_to_string(node_id));
604         // return quickly for things in the same module
605         if self.parents.get(&node_id) == self.parents.get(&self.curitem) {
606             debug!("privacy - same parent, we're done here");
607             return Allowable;
608         }
609
610         // We now know that there is at least one private member between the
611         // destination and the root.
612         let mut closest_private_id = node_id;
613         loop {
614             debug!("privacy - examining {}", self.nodestr(closest_private_id));
615             let vis = match self.tcx.map.find(closest_private_id) {
616                 // If this item is a method, then we know for sure that it's an
617                 // actual method and not a static method. The reason for this is
618                 // that these cases are only hit in the ExprMethodCall
619                 // expression, and ExprCall will have its path checked later
620                 // (the path of the trait/impl) if it's a static method.
621                 //
622                 // With this information, then we can completely ignore all
623                 // trait methods. The privacy violation would be if the trait
624                 // couldn't get imported, not if the method couldn't be used
625                 // (all trait methods are public).
626                 //
627                 // However, if this is an impl method, then we dictate this
628                 // decision solely based on the privacy of the method
629                 // invocation.
630                 // FIXME(#10573) is this the right behavior? Why not consider
631                 //               where the method was defined?
632                 Some(ast_map::NodeImplItem(ii)) => {
633                     match ii.node {
634                         hir::ImplItemKind::Const(..) |
635                         hir::ImplItemKind::Method(..) => {
636                             let imp = self.tcx.map
637                                           .get_parent_did(closest_private_id);
638                             match self.tcx.impl_trait_ref(imp) {
639                                 Some(..) => return Allowable,
640                                 _ if ii.vis == hir::Public => {
641                                     return Allowable
642                                 }
643                                 _ => ii.vis
644                             }
645                         }
646                         hir::ImplItemKind::Type(_) => return Allowable,
647                     }
648                 }
649                 Some(ast_map::NodeTraitItem(_)) => {
650                     return Allowable;
651                 }
652
653                 // This is not a method call, extract the visibility as one
654                 // would normally look at it
655                 Some(ast_map::NodeItem(it)) => it.vis,
656                 Some(ast_map::NodeForeignItem(_)) => {
657                     self.tcx.map.get_foreign_vis(closest_private_id)
658                 }
659                 Some(ast_map::NodeVariant(..)) => {
660                     hir::Public // need to move up a level (to the enum)
661                 }
662                 _ => hir::Public,
663             };
664             if vis != hir::Public { break }
665             // if we've reached the root, then everything was allowable and this
666             // access is public.
667             if closest_private_id == ast::CRATE_NODE_ID { return Allowable }
668             closest_private_id = *self.parents.get(&closest_private_id).unwrap();
669
670             // If we reached the top, then we were public all the way down and
671             // we can allow this access.
672             if closest_private_id == ast::DUMMY_NODE_ID { return Allowable }
673         }
674         debug!("privacy - closest priv {}", self.nodestr(closest_private_id));
675         if self.private_accessible(closest_private_id) {
676             Allowable
677         } else {
678             DisallowedBy(closest_private_id)
679         }
680     }
681
682     /// True if `id` is both local and private-accessible
683     fn local_private_accessible(&self, did: DefId) -> bool {
684         if let Some(node_id) = self.tcx.map.as_local_node_id(did) {
685             self.private_accessible(node_id)
686         } else {
687             false
688         }
689     }
690
691     /// For a local private node in the AST, this function will determine
692     /// whether the node is accessible by the current module that iteration is
693     /// inside.
694     fn private_accessible(&self, id: ast::NodeId) -> bool {
695         let parent = *self.parents.get(&id).unwrap();
696         debug!("privacy - accessible parent {}", self.nodestr(parent));
697
698         // After finding `did`'s closest private member, we roll ourselves back
699         // to see if this private member's parent is anywhere in our ancestry.
700         // By the privacy rules, we can access all of our ancestor's private
701         // members, so that's why we test the parent, and not the did itself.
702         let mut cur = self.curitem;
703         loop {
704             debug!("privacy - questioning {}, {}", self.nodestr(cur), cur);
705             match cur {
706                 // If the relevant parent is in our history, then we're allowed
707                 // to look inside any of our ancestor's immediate private items,
708                 // so this access is valid.
709                 x if x == parent => return true,
710
711                 // If we've reached the root, then we couldn't access this item
712                 // in the first place
713                 ast::DUMMY_NODE_ID => return false,
714
715                 // Keep going up
716                 _ => {}
717             }
718
719             cur = *self.parents.get(&cur).unwrap();
720         }
721     }
722
723     fn report_error(&self, result: CheckResult) -> bool {
724         match result {
725             None => true,
726             Some((span, msg, note)) => {
727                 let mut err = self.tcx.sess.struct_span_err(span, &msg[..]);
728                 if let Some((span, msg)) = note {
729                     err.span_note(span, &msg[..]);
730                 }
731                 err.emit();
732                 false
733             },
734         }
735     }
736
737     /// Guarantee that a particular definition is public. Returns a CheckResult
738     /// which contains any errors found. These can be reported using `report_error`.
739     /// If the result is `None`, no errors were found.
740     fn ensure_public(&self,
741                      span: Span,
742                      to_check: DefId,
743                      source_did: Option<DefId>,
744                      msg: &str)
745                      -> CheckResult {
746         use rustc_front::hir::Item_::ItemExternCrate;
747         debug!("ensure_public(span={:?}, to_check={:?}, source_did={:?}, msg={:?})",
748                span, to_check, source_did, msg);
749         let def_privacy = self.def_privacy(to_check);
750         debug!("ensure_public: def_privacy={:?}", def_privacy);
751         let id = match def_privacy {
752             ExternallyDenied => {
753                 return Some((span, format!("{} is private", msg), None))
754             }
755             Allowable => return None,
756             DisallowedBy(id) => id,
757         };
758
759         // If we're disallowed by a particular id, then we attempt to
760         // give a nice error message to say why it was disallowed. It
761         // was either because the item itself is private or because
762         // its parent is private and its parent isn't in our
763         // ancestry. (Both the item being checked and its parent must
764         // be local.)
765         let def_id = source_did.unwrap_or(to_check);
766         let node_id = self.tcx.map.as_local_node_id(def_id);
767
768         // Warn when using a inaccessible extern crate.
769         if let Some(node_id) = self.tcx.map.as_local_node_id(to_check) {
770             match self.tcx.map.get(node_id) {
771                 ast_map::Node::NodeItem(&hir::Item { node: ItemExternCrate(_), name, .. }) => {
772                     self.tcx.sess.add_lint(lint::builtin::INACCESSIBLE_EXTERN_CRATE,
773                                            node_id,
774                                            span,
775                                            format!("extern crate `{}` is private", name));
776                     return None;
777                 }
778                 _ => {}
779             }
780         }
781
782         let (err_span, err_msg) = if Some(id) == node_id {
783             return Some((span, format!("{} is private", msg), None));
784         } else {
785             (span, format!("{} is inaccessible", msg))
786         };
787         let item = match self.tcx.map.find(id) {
788             Some(ast_map::NodeItem(item)) => {
789                 match item.node {
790                     // If an impl disallowed this item, then this is resolve's
791                     // way of saying that a struct/enum's static method was
792                     // invoked, and the struct/enum itself is private. Crawl
793                     // back up the chains to find the relevant struct/enum that
794                     // was private.
795                     hir::ItemImpl(_, _, _, _, ref ty, _) => {
796                         match ty.node {
797                             hir::TyPath(..) => {}
798                             _ => return Some((err_span, err_msg, None)),
799                         };
800                         let def = self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def();
801                         let did = def.def_id();
802                         let node_id = self.tcx.map.as_local_node_id(did).unwrap();
803                         match self.tcx.map.get(node_id) {
804                             ast_map::NodeItem(item) => item,
805                             _ => self.tcx.sess.span_bug(item.span,
806                                                         "path is not an item")
807                         }
808                     }
809                     _ => item
810                 }
811             }
812             Some(..) | None => return Some((err_span, err_msg, None)),
813         };
814         let desc = match item.node {
815             hir::ItemMod(..) => "module",
816             hir::ItemTrait(..) => "trait",
817             hir::ItemStruct(..) => "struct",
818             hir::ItemEnum(..) => "enum",
819             _ => return Some((err_span, err_msg, None))
820         };
821         let msg = format!("{} `{}` is private", desc, item.name);
822         Some((err_span, err_msg, Some((span, msg))))
823     }
824
825     // Checks that a field is in scope.
826     fn check_field(&mut self,
827                    span: Span,
828                    def: ty::AdtDef<'tcx>,
829                    v: ty::VariantDef<'tcx>,
830                    name: FieldName) {
831         let field = match name {
832             NamedField(f_name) => {
833                 debug!("privacy - check named field {} in struct {:?}", f_name, def);
834                 v.field_named(f_name)
835             }
836             UnnamedField(idx) => &v.fields[idx]
837         };
838         if field.vis == hir::Public || self.local_private_accessible(field.did) {
839             return;
840         }
841
842         let struct_desc = match def.adt_kind() {
843             ty::AdtKind::Struct =>
844                 format!("struct `{}`", self.tcx.item_path_str(def.did)),
845             // struct variant fields have inherited visibility
846             ty::AdtKind::Enum => return
847         };
848         let msg = match name {
849             NamedField(name) => format!("field `{}` of {} is private",
850                                         name, struct_desc),
851             UnnamedField(idx) => format!("field #{} of {} is private",
852                                          idx, struct_desc),
853         };
854         span_err!(self.tcx.sess, span, E0451,
855                   "{}", &msg[..]);
856     }
857
858     // Given the ID of a method, checks to ensure it's in scope.
859     fn check_static_method(&mut self,
860                            span: Span,
861                            method_id: DefId,
862                            name: ast::Name) {
863         self.report_error(self.ensure_public(span,
864                                              method_id,
865                                              None,
866                                              &format!("method `{}`",
867                                                      name)));
868     }
869
870     // Checks that a path is in scope.
871     fn check_path(&mut self, span: Span, path_id: ast::NodeId, last: ast::Name) {
872         debug!("privacy - path {}", self.nodestr(path_id));
873         let path_res = *self.tcx.def_map.borrow().get(&path_id).unwrap();
874         let ck = |tyname: &str| {
875             let ck_public = |def: DefId| {
876                 debug!("privacy - ck_public {:?}", def);
877                 let origdid = path_res.def_id();
878                 self.ensure_public(span,
879                                    def,
880                                    Some(origdid),
881                                    &format!("{} `{}`", tyname, last))
882             };
883
884             match path_res.last_private {
885                 LastMod(AllPublic) => {},
886                 LastMod(DependsOn(def)) => {
887                     self.report_error(ck_public(def));
888                 },
889                 LastImport { value_priv,
890                              value_used: check_value,
891                              type_priv,
892                              type_used: check_type } => {
893                     // This dance with found_error is because we don't want to
894                     // report a privacy error twice for the same directive.
895                     let found_error = match (type_priv, check_type) {
896                         (Some(DependsOn(def)), Used) => {
897                             !self.report_error(ck_public(def))
898                         },
899                         _ => false,
900                     };
901                     if !found_error {
902                         match (value_priv, check_value) {
903                             (Some(DependsOn(def)), Used) => {
904                                 self.report_error(ck_public(def));
905                             },
906                             _ => {},
907                         }
908                     }
909                     // If an import is not used in either namespace, we still
910                     // want to check that it could be legal. Therefore we check
911                     // in both namespaces and only report an error if both would
912                     // be illegal. We only report one error, even if it is
913                     // illegal to import from both namespaces.
914                     match (value_priv, check_value, type_priv, check_type) {
915                         (Some(p), Unused, None, _) |
916                         (None, _, Some(p), Unused) => {
917                             let p = match p {
918                                 AllPublic => None,
919                                 DependsOn(def) => ck_public(def),
920                             };
921                             if p.is_some() {
922                                 self.report_error(p);
923                             }
924                         },
925                         (Some(v), Unused, Some(t), Unused) => {
926                             let v = match v {
927                                 AllPublic => None,
928                                 DependsOn(def) => ck_public(def),
929                             };
930                             let t = match t {
931                                 AllPublic => None,
932                                 DependsOn(def) => ck_public(def),
933                             };
934                             if let (Some(_), Some(t)) = (v, t) {
935                                 self.report_error(Some(t));
936                             }
937                         },
938                         _ => {},
939                     }
940                 },
941             }
942         };
943         // FIXME(#12334) Imports can refer to definitions in both the type and
944         // value namespaces. The privacy information is aware of this, but the
945         // def map is not. Therefore the names we work out below will not always
946         // be accurate and we can get slightly wonky error messages (but type
947         // checking is always correct).
948         match path_res.full_def() {
949             Def::Fn(..) => ck("function"),
950             Def::Static(..) => ck("static"),
951             Def::Const(..) => ck("const"),
952             Def::AssociatedConst(..) => ck("associated const"),
953             Def::Variant(..) => ck("variant"),
954             Def::TyAlias(..) => ck("type"),
955             Def::Enum(..) => ck("enum"),
956             Def::Trait(..) => ck("trait"),
957             Def::Struct(..) => ck("struct"),
958             Def::Method(..) => ck("method"),
959             Def::Mod(..) => ck("module"),
960             _ => {}
961         }
962     }
963
964     // Checks that a method is in scope.
965     fn check_method(&mut self, span: Span, method_def_id: DefId,
966                     name: ast::Name) {
967         match self.tcx.impl_or_trait_item(method_def_id).container() {
968             ty::ImplContainer(_) => {
969                 self.check_static_method(span, method_def_id, name)
970             }
971             // Trait methods are always all public. The only controlling factor
972             // is whether the trait itself is accessible or not.
973             ty::TraitContainer(trait_def_id) => {
974                 self.report_error(self.ensure_public(span, trait_def_id,
975                                                      None, "source trait"));
976             }
977         }
978     }
979 }
980
981 impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
982     /// We want to visit items in the context of their containing
983     /// module and so forth, so supply a crate for doing a deep walk.
984     fn visit_nested_item(&mut self, item: hir::ItemId) {
985         self.visit_item(self.tcx.map.expect_item(item.id))
986     }
987
988     fn visit_item(&mut self, item: &hir::Item) {
989         let orig_curitem = replace(&mut self.curitem, item.id);
990         intravisit::walk_item(self, item);
991         self.curitem = orig_curitem;
992     }
993
994     fn visit_expr(&mut self, expr: &hir::Expr) {
995         match expr.node {
996             hir::ExprField(ref base, name) => {
997                 if let ty::TyStruct(def, _) = self.tcx.expr_ty_adjusted(&base).sty {
998                     self.check_field(expr.span,
999                                      def,
1000                                      def.struct_variant(),
1001                                      NamedField(name.node));
1002                 }
1003             }
1004             hir::ExprTupField(ref base, idx) => {
1005                 if let ty::TyStruct(def, _) = self.tcx.expr_ty_adjusted(&base).sty {
1006                     self.check_field(expr.span,
1007                                      def,
1008                                      def.struct_variant(),
1009                                      UnnamedField(idx.node));
1010                 }
1011             }
1012             hir::ExprMethodCall(name, _, _) => {
1013                 let method_call = ty::MethodCall::expr(expr.id);
1014                 let method = self.tcx.tables.borrow().method_map[&method_call];
1015                 debug!("(privacy checking) checking impl method");
1016                 self.check_method(expr.span, method.def_id, name.node);
1017             }
1018             hir::ExprStruct(..) => {
1019                 let adt = self.tcx.expr_ty(expr).ty_adt_def().unwrap();
1020                 let variant = adt.variant_of_def(self.tcx.resolve_expr(expr));
1021                 // RFC 736: ensure all unmentioned fields are visible.
1022                 // Rather than computing the set of unmentioned fields
1023                 // (i.e. `all_fields - fields`), just check them all.
1024                 for field in &variant.fields {
1025                     self.check_field(expr.span, adt, variant, NamedField(field.name));
1026                 }
1027             }
1028             hir::ExprPath(..) => {
1029
1030                 if let Def::Struct(..) = self.tcx.resolve_expr(expr) {
1031                     let expr_ty = self.tcx.expr_ty(expr);
1032                     let def = match expr_ty.sty {
1033                         ty::TyBareFn(_, &ty::BareFnTy { sig: ty::Binder(ty::FnSig {
1034                             output: ty::FnConverging(ty), ..
1035                         }), ..}) => ty,
1036                         _ => expr_ty
1037                     }.ty_adt_def().unwrap();
1038                     let any_priv = def.struct_variant().fields.iter().any(|f| {
1039                         f.vis != hir::Public && !self.local_private_accessible(f.did)
1040                     });
1041                     if any_priv {
1042                         span_err!(self.tcx.sess, expr.span, E0450,
1043                                   "cannot invoke tuple struct constructor with private \
1044                                    fields");
1045                     }
1046                 }
1047             }
1048             _ => {}
1049         }
1050
1051         intravisit::walk_expr(self, expr);
1052     }
1053
1054     fn visit_pat(&mut self, pattern: &hir::Pat) {
1055         // Foreign functions do not have their patterns mapped in the def_map,
1056         // and there's nothing really relevant there anyway, so don't bother
1057         // checking privacy. If you can name the type then you can pass it to an
1058         // external C function anyway.
1059         if self.in_foreign { return }
1060
1061         match pattern.node {
1062             PatKind::Struct(_, ref fields, _) => {
1063                 let adt = self.tcx.pat_ty(pattern).ty_adt_def().unwrap();
1064                 let def = self.tcx.def_map.borrow().get(&pattern.id).unwrap().full_def();
1065                 let variant = adt.variant_of_def(def);
1066                 for field in fields {
1067                     self.check_field(pattern.span, adt, variant,
1068                                      NamedField(field.node.name));
1069                 }
1070             }
1071
1072             // Patterns which bind no fields are allowable (the path is check
1073             // elsewhere).
1074             PatKind::TupleStruct(_, Some(ref fields)) => {
1075                 match self.tcx.pat_ty(pattern).sty {
1076                     ty::TyStruct(def, _) => {
1077                         for (i, field) in fields.iter().enumerate() {
1078                             if let PatKind::Wild = field.node {
1079                                 continue
1080                             }
1081                             self.check_field(field.span,
1082                                              def,
1083                                              def.struct_variant(),
1084                                              UnnamedField(i));
1085                         }
1086                     }
1087                     ty::TyEnum(..) => {
1088                         // enum fields have no privacy at this time
1089                     }
1090                     _ => {}
1091                 }
1092
1093             }
1094             _ => {}
1095         }
1096
1097         intravisit::walk_pat(self, pattern);
1098     }
1099
1100     fn visit_foreign_item(&mut self, fi: &hir::ForeignItem) {
1101         self.in_foreign = true;
1102         intravisit::walk_foreign_item(self, fi);
1103         self.in_foreign = false;
1104     }
1105
1106     fn visit_path(&mut self, path: &hir::Path, id: ast::NodeId) {
1107         if !path.segments.is_empty() {
1108             self.check_path(path.span, id, path.segments.last().unwrap().identifier.name);
1109             intravisit::walk_path(self, path);
1110         }
1111     }
1112
1113     fn visit_path_list_item(&mut self, prefix: &hir::Path, item: &hir::PathListItem) {
1114         let name = if let hir::PathListIdent { name, .. } = item.node {
1115             name
1116         } else if !prefix.segments.is_empty() {
1117             prefix.segments.last().unwrap().identifier.name
1118         } else {
1119             self.tcx.sess.bug("`self` import in an import list with empty prefix");
1120         };
1121         self.check_path(item.span, item.node.id(), name);
1122         intravisit::walk_path_list_item(self, prefix, item);
1123     }
1124 }
1125
1126 ////////////////////////////////////////////////////////////////////////////////
1127 /// The privacy sanity check visitor, ensures unnecessary visibility isn't here
1128 ////////////////////////////////////////////////////////////////////////////////
1129
1130 struct SanePrivacyVisitor<'a, 'tcx: 'a> {
1131     tcx: &'a ty::ctxt<'tcx>,
1132 }
1133
1134 impl<'a, 'tcx, 'v> Visitor<'v> for SanePrivacyVisitor<'a, 'tcx> {
1135     fn visit_item(&mut self, item: &hir::Item) {
1136         self.check_sane_privacy(item);
1137         intravisit::walk_item(self, item);
1138     }
1139 }
1140
1141 impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> {
1142     /// Validate that items that shouldn't have visibility qualifiers don't have them.
1143     /// Such qualifiers can be set by syntax extensions even if the parser doesn't allow them,
1144     /// so we check things like variant fields too.
1145     fn check_sane_privacy(&self, item: &hir::Item) {
1146         let check_inherited = |sp, vis, note: &str| {
1147             if vis != hir::Inherited {
1148                 let mut err = struct_span_err!(self.tcx.sess, sp, E0449,
1149                                                "unnecessary visibility qualifier");
1150                 if !note.is_empty() {
1151                     err.span_note(sp, note);
1152                 }
1153                 err.emit();
1154             }
1155         };
1156
1157         match item.node {
1158             hir::ItemImpl(_, _, _, Some(..), _, ref impl_items) => {
1159                 check_inherited(item.span, item.vis,
1160                                 "visibility qualifiers have no effect on trait impls");
1161                 for impl_item in impl_items {
1162                     check_inherited(impl_item.span, impl_item.vis,
1163                                     "visibility qualifiers have no effect on trait impl items");
1164                 }
1165             }
1166             hir::ItemImpl(_, _, _, None, _, _) => {
1167                 check_inherited(item.span, item.vis,
1168                                 "place qualifiers on individual methods instead");
1169             }
1170             hir::ItemDefaultImpl(..) => {
1171                 check_inherited(item.span, item.vis,
1172                                 "visibility qualifiers have no effect on trait impls");
1173             }
1174             hir::ItemForeignMod(..) => {
1175                 check_inherited(item.span, item.vis,
1176                                 "place qualifiers on individual functions instead");
1177             }
1178             hir::ItemEnum(ref def, _) => {
1179                 for variant in &def.variants {
1180                     for field in variant.node.data.fields() {
1181                         check_inherited(field.span, field.node.kind.visibility(),
1182                                         "visibility qualifiers have no effect on variant fields");
1183                     }
1184                 }
1185             }
1186             hir::ItemStruct(..) | hir::ItemTrait(..) |
1187             hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) |
1188             hir::ItemMod(..) | hir::ItemExternCrate(..) |
1189             hir::ItemUse(..) | hir::ItemTy(..) => {}
1190         }
1191     }
1192 }
1193
1194 ///////////////////////////////////////////////////////////////////////////////
1195 /// Obsolete visitors for checking for private items in public interfaces.
1196 /// These visitors are supposed to be kept in frozen state and produce an
1197 /// "old error node set". For backward compatibility the new visitor reports
1198 /// warnings instead of hard errors when the erroneous node is not in this old set.
1199 ///////////////////////////////////////////////////////////////////////////////
1200
1201 struct ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx: 'a> {
1202     tcx: &'a ty::ctxt<'tcx>,
1203     access_levels: &'a AccessLevels,
1204     in_variant: bool,
1205     // set of errors produced by this obsolete visitor
1206     old_error_set: NodeSet,
1207 }
1208
1209 struct ObsoleteCheckTypeForPrivatenessVisitor<'a, 'b: 'a, 'tcx: 'b> {
1210     inner: &'a ObsoleteVisiblePrivateTypesVisitor<'b, 'tcx>,
1211     /// whether the type refers to private types.
1212     contains_private: bool,
1213     /// whether we've recurred at all (i.e. if we're pointing at the
1214     /// first type on which visit_ty was called).
1215     at_outer_type: bool,
1216     // whether that first type is a public path.
1217     outer_type_is_public_path: bool,
1218 }
1219
1220 impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
1221     fn path_is_private_type(&self, path_id: ast::NodeId) -> bool {
1222         let did = match self.tcx.def_map.borrow().get(&path_id).map(|d| d.full_def()) {
1223             // `int` etc. (None doesn't seem to occur.)
1224             None | Some(Def::PrimTy(..)) | Some(Def::SelfTy(..)) => return false,
1225             Some(def) => def.def_id(),
1226         };
1227
1228         // A path can only be private if:
1229         // it's in this crate...
1230         if let Some(node_id) = self.tcx.map.as_local_node_id(did) {
1231             // .. and it corresponds to a private type in the AST (this returns
1232             // None for type parameters)
1233             match self.tcx.map.find(node_id) {
1234                 Some(ast_map::NodeItem(ref item)) => item.vis != hir::Public,
1235                 Some(_) | None => false,
1236             }
1237         } else {
1238             return false
1239         }
1240     }
1241
1242     fn trait_is_public(&self, trait_id: ast::NodeId) -> bool {
1243         // FIXME: this would preferably be using `exported_items`, but all
1244         // traits are exported currently (see `EmbargoVisitor.exported_trait`)
1245         self.access_levels.is_public(trait_id)
1246     }
1247
1248     fn check_ty_param_bound(&mut self,
1249                             ty_param_bound: &hir::TyParamBound) {
1250         if let hir::TraitTyParamBound(ref trait_ref, _) = *ty_param_bound {
1251             if self.path_is_private_type(trait_ref.trait_ref.ref_id) {
1252                 self.old_error_set.insert(trait_ref.trait_ref.ref_id);
1253             }
1254         }
1255     }
1256
1257     fn item_is_public(&self, id: &ast::NodeId, vis: hir::Visibility) -> bool {
1258         self.access_levels.is_reachable(*id) || vis == hir::Public
1259     }
1260 }
1261
1262 impl<'a, 'b, 'tcx, 'v> Visitor<'v> for ObsoleteCheckTypeForPrivatenessVisitor<'a, 'b, 'tcx> {
1263     fn visit_ty(&mut self, ty: &hir::Ty) {
1264         if let hir::TyPath(..) = ty.node {
1265             if self.inner.path_is_private_type(ty.id) {
1266                 self.contains_private = true;
1267                 // found what we're looking for so let's stop
1268                 // working.
1269                 return
1270             } else if self.at_outer_type {
1271                 self.outer_type_is_public_path = true;
1272             }
1273         }
1274         self.at_outer_type = false;
1275         intravisit::walk_ty(self, ty)
1276     }
1277
1278     // don't want to recurse into [, .. expr]
1279     fn visit_expr(&mut self, _: &hir::Expr) {}
1280 }
1281
1282 impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
1283     /// We want to visit items in the context of their containing
1284     /// module and so forth, so supply a crate for doing a deep walk.
1285     fn visit_nested_item(&mut self, item: hir::ItemId) {
1286         self.visit_item(self.tcx.map.expect_item(item.id))
1287     }
1288
1289     fn visit_item(&mut self, item: &hir::Item) {
1290         match item.node {
1291             // contents of a private mod can be reexported, so we need
1292             // to check internals.
1293             hir::ItemMod(_) => {}
1294
1295             // An `extern {}` doesn't introduce a new privacy
1296             // namespace (the contents have their own privacies).
1297             hir::ItemForeignMod(_) => {}
1298
1299             hir::ItemTrait(_, _, ref bounds, _) => {
1300                 if !self.trait_is_public(item.id) {
1301                     return
1302                 }
1303
1304                 for bound in bounds.iter() {
1305                     self.check_ty_param_bound(bound)
1306                 }
1307             }
1308
1309             // impls need some special handling to try to offer useful
1310             // error messages without (too many) false positives
1311             // (i.e. we could just return here to not check them at
1312             // all, or some worse estimation of whether an impl is
1313             // publicly visible).
1314             hir::ItemImpl(_, _, ref g, ref trait_ref, ref self_, ref impl_items) => {
1315                 // `impl [... for] Private` is never visible.
1316                 let self_contains_private;
1317                 // impl [... for] Public<...>, but not `impl [... for]
1318                 // Vec<Public>` or `(Public,)` etc.
1319                 let self_is_public_path;
1320
1321                 // check the properties of the Self type:
1322                 {
1323                     let mut visitor = ObsoleteCheckTypeForPrivatenessVisitor {
1324                         inner: self,
1325                         contains_private: false,
1326                         at_outer_type: true,
1327                         outer_type_is_public_path: false,
1328                     };
1329                     visitor.visit_ty(&self_);
1330                     self_contains_private = visitor.contains_private;
1331                     self_is_public_path = visitor.outer_type_is_public_path;
1332                 }
1333
1334                 // miscellaneous info about the impl
1335
1336                 // `true` iff this is `impl Private for ...`.
1337                 let not_private_trait =
1338                     trait_ref.as_ref().map_or(true, // no trait counts as public trait
1339                                               |tr| {
1340                         let did = self.tcx.trait_ref_to_def_id(tr);
1341
1342                         if let Some(node_id) = self.tcx.map.as_local_node_id(did) {
1343                             self.trait_is_public(node_id)
1344                         } else {
1345                             true // external traits must be public
1346                         }
1347                     });
1348
1349                 // `true` iff this is a trait impl or at least one method is public.
1350                 //
1351                 // `impl Public { $( fn ...() {} )* }` is not visible.
1352                 //
1353                 // This is required over just using the methods' privacy
1354                 // directly because we might have `impl<T: Foo<Private>> ...`,
1355                 // and we shouldn't warn about the generics if all the methods
1356                 // are private (because `T` won't be visible externally).
1357                 let trait_or_some_public_method =
1358                     trait_ref.is_some() ||
1359                     impl_items.iter()
1360                               .any(|impl_item| {
1361                                   match impl_item.node {
1362                                       hir::ImplItemKind::Const(..) |
1363                                       hir::ImplItemKind::Method(..) => {
1364                                           self.access_levels.is_reachable(impl_item.id)
1365                                       }
1366                                       hir::ImplItemKind::Type(_) => false,
1367                                   }
1368                               });
1369
1370                 if !self_contains_private &&
1371                         not_private_trait &&
1372                         trait_or_some_public_method {
1373
1374                     intravisit::walk_generics(self, g);
1375
1376                     match *trait_ref {
1377                         None => {
1378                             for impl_item in impl_items {
1379                                 // This is where we choose whether to walk down
1380                                 // further into the impl to check its items. We
1381                                 // should only walk into public items so that we
1382                                 // don't erroneously report errors for private
1383                                 // types in private items.
1384                                 match impl_item.node {
1385                                     hir::ImplItemKind::Const(..) |
1386                                     hir::ImplItemKind::Method(..)
1387                                         if self.item_is_public(&impl_item.id, impl_item.vis) =>
1388                                     {
1389                                         intravisit::walk_impl_item(self, impl_item)
1390                                     }
1391                                     hir::ImplItemKind::Type(..) => {
1392                                         intravisit::walk_impl_item(self, impl_item)
1393                                     }
1394                                     _ => {}
1395                                 }
1396                             }
1397                         }
1398                         Some(ref tr) => {
1399                             // Any private types in a trait impl fall into three
1400                             // categories.
1401                             // 1. mentioned in the trait definition
1402                             // 2. mentioned in the type params/generics
1403                             // 3. mentioned in the associated types of the impl
1404                             //
1405                             // Those in 1. can only occur if the trait is in
1406                             // this crate and will've been warned about on the
1407                             // trait definition (there's no need to warn twice
1408                             // so we don't check the methods).
1409                             //
1410                             // Those in 2. are warned via walk_generics and this
1411                             // call here.
1412                             intravisit::walk_path(self, &tr.path);
1413
1414                             // Those in 3. are warned with this call.
1415                             for impl_item in impl_items {
1416                                 if let hir::ImplItemKind::Type(ref ty) = impl_item.node {
1417                                     self.visit_ty(ty);
1418                                 }
1419                             }
1420                         }
1421                     }
1422                 } else if trait_ref.is_none() && self_is_public_path {
1423                     // impl Public<Private> { ... }. Any public static
1424                     // methods will be visible as `Public::foo`.
1425                     let mut found_pub_static = false;
1426                     for impl_item in impl_items {
1427                         match impl_item.node {
1428                             hir::ImplItemKind::Const(..) => {
1429                                 if self.item_is_public(&impl_item.id, impl_item.vis) {
1430                                     found_pub_static = true;
1431                                     intravisit::walk_impl_item(self, impl_item);
1432                                 }
1433                             }
1434                             hir::ImplItemKind::Method(ref sig, _) => {
1435                                 if sig.explicit_self.node == hir::SelfStatic &&
1436                                       self.item_is_public(&impl_item.id, impl_item.vis) {
1437                                     found_pub_static = true;
1438                                     intravisit::walk_impl_item(self, impl_item);
1439                                 }
1440                             }
1441                             _ => {}
1442                         }
1443                     }
1444                     if found_pub_static {
1445                         intravisit::walk_generics(self, g)
1446                     }
1447                 }
1448                 return
1449             }
1450
1451             // `type ... = ...;` can contain private types, because
1452             // we're introducing a new name.
1453             hir::ItemTy(..) => return,
1454
1455             // not at all public, so we don't care
1456             _ if !self.item_is_public(&item.id, item.vis) => {
1457                 return;
1458             }
1459
1460             _ => {}
1461         }
1462
1463         // We've carefully constructed it so that if we're here, then
1464         // any `visit_ty`'s will be called on things that are in
1465         // public signatures, i.e. things that we're interested in for
1466         // this visitor.
1467         debug!("VisiblePrivateTypesVisitor entering item {:?}", item);
1468         intravisit::walk_item(self, item);
1469     }
1470
1471     fn visit_generics(&mut self, generics: &hir::Generics) {
1472         for ty_param in generics.ty_params.iter() {
1473             for bound in ty_param.bounds.iter() {
1474                 self.check_ty_param_bound(bound)
1475             }
1476         }
1477         for predicate in &generics.where_clause.predicates {
1478             match predicate {
1479                 &hir::WherePredicate::BoundPredicate(ref bound_pred) => {
1480                     for bound in bound_pred.bounds.iter() {
1481                         self.check_ty_param_bound(bound)
1482                     }
1483                 }
1484                 &hir::WherePredicate::RegionPredicate(_) => {}
1485                 &hir::WherePredicate::EqPredicate(ref eq_pred) => {
1486                     self.visit_ty(&eq_pred.ty);
1487                 }
1488             }
1489         }
1490     }
1491
1492     fn visit_foreign_item(&mut self, item: &hir::ForeignItem) {
1493         if self.access_levels.is_reachable(item.id) {
1494             intravisit::walk_foreign_item(self, item)
1495         }
1496     }
1497
1498     fn visit_ty(&mut self, t: &hir::Ty) {
1499         debug!("VisiblePrivateTypesVisitor checking ty {:?}", t);
1500         if let hir::TyPath(..) = t.node {
1501             if self.path_is_private_type(t.id) {
1502                 self.old_error_set.insert(t.id);
1503             }
1504         }
1505         intravisit::walk_ty(self, t)
1506     }
1507
1508     fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics, item_id: ast::NodeId) {
1509         if self.access_levels.is_reachable(v.node.data.id()) {
1510             self.in_variant = true;
1511             intravisit::walk_variant(self, v, g, item_id);
1512             self.in_variant = false;
1513         }
1514     }
1515
1516     fn visit_struct_field(&mut self, s: &hir::StructField) {
1517         let vis = match s.node.kind {
1518             hir::NamedField(_, vis) | hir::UnnamedField(vis) => vis
1519         };
1520         if vis == hir::Public || self.in_variant {
1521             intravisit::walk_struct_field(self, s);
1522         }
1523     }
1524
1525     // we don't need to introspect into these at all: an
1526     // expression/block context can't possibly contain exported things.
1527     // (Making them no-ops stops us from traversing the whole AST without
1528     // having to be super careful about our `walk_...` calls above.)
1529     // FIXME(#29524): Unfortunately this ^^^ is not true, blocks can contain
1530     // exported items (e.g. impls) and actual code in rustc itself breaks
1531     // if we don't traverse blocks in `EmbargoVisitor`
1532     fn visit_block(&mut self, _: &hir::Block) {}
1533     fn visit_expr(&mut self, _: &hir::Expr) {}
1534 }
1535
1536 ///////////////////////////////////////////////////////////////////////////////
1537 /// SearchInterfaceForPrivateItemsVisitor traverses an item's interface and
1538 /// finds any private components in it.
1539 /// PrivateItemsInPublicInterfacesVisitor ensures there are no private types
1540 /// and traits in public interfaces.
1541 ///////////////////////////////////////////////////////////////////////////////
1542
1543 struct SearchInterfaceForPrivateItemsVisitor<'a, 'tcx: 'a> {
1544     tcx: &'a ty::ctxt<'tcx>,
1545     // Do not report an error when a private type is found
1546     is_quiet: bool,
1547     // Is private component found?
1548     is_public: bool,
1549     old_error_set: &'a NodeSet,
1550 }
1551
1552 impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
1553     // Check if the type alias contain private types when substituted
1554     fn is_public_type_alias(&self, item: &hir::Item, path: &hir::Path) -> bool {
1555         // We substitute type aliases only when determining impl publicity
1556         // FIXME: This will probably change and all type aliases will be substituted,
1557         // requires an amendment to RFC 136.
1558         if !self.is_quiet {
1559             return false
1560         }
1561         // Type alias is considered public if the aliased type is
1562         // public, even if the type alias itself is private. So, something
1563         // like `type A = u8; pub fn f() -> A {...}` doesn't cause an error.
1564         if let hir::ItemTy(ref ty, ref generics) = item.node {
1565             let mut check = SearchInterfaceForPrivateItemsVisitor { is_public: true, ..*self };
1566             check.visit_ty(ty);
1567             // If a private type alias with default type parameters is used in public
1568             // interface we must ensure, that the defaults are public if they are actually used.
1569             // ```
1570             // type Alias<T = Private> = T;
1571             // pub fn f() -> Alias {...} // `Private` is implicitly used here, so it must be public
1572             // ```
1573             let provided_params = path.segments.last().unwrap().parameters.types().len();
1574             for ty_param in &generics.ty_params[provided_params..] {
1575                 if let Some(ref default_ty) = ty_param.default {
1576                     check.visit_ty(default_ty);
1577                 }
1578             }
1579             check.is_public
1580         } else {
1581             false
1582         }
1583     }
1584 }
1585
1586 impl<'a, 'tcx: 'a, 'v> Visitor<'v> for SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
1587     fn visit_ty(&mut self, ty: &hir::Ty) {
1588         if self.is_quiet && !self.is_public {
1589             // We are in quiet mode and a private type is already found, no need to proceed
1590             return
1591         }
1592         if let hir::TyPath(_, ref path) = ty.node {
1593             let def = self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def();
1594             match def {
1595                 Def::PrimTy(..) | Def::SelfTy(..) | Def::TyParam(..) => {
1596                     // Public
1597                 }
1598                 Def::AssociatedTy(..) if self.is_quiet => {
1599                     // Conservatively approximate the whole type alias as public without
1600                     // recursing into its components when determining impl publicity.
1601                     // For example, `impl <Type as Trait>::Alias {...}` may be a public impl
1602                     // even if both `Type` and `Trait` are private.
1603                     // Ideally, associated types should be substituted in the same way as
1604                     // free type aliases, but this isn't done yet.
1605                     return
1606                 }
1607                 Def::Struct(def_id) | Def::Enum(def_id) | Def::TyAlias(def_id) |
1608                 Def::Trait(def_id) | Def::AssociatedTy(def_id, _) => {
1609                     // Non-local means public (private items can't leave their crate, modulo bugs)
1610                     if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
1611                         let item = self.tcx.map.expect_item(node_id);
1612                         if item.vis != hir::Public && !self.is_public_type_alias(item, path) {
1613                             if !self.is_quiet {
1614                                 if self.old_error_set.contains(&ty.id) {
1615                                     span_err!(self.tcx.sess, ty.span, E0446,
1616                                               "private type in public interface");
1617                                 } else {
1618                                     self.tcx.sess.add_lint (
1619                                         lint::builtin::PRIVATE_IN_PUBLIC,
1620                                         node_id,
1621                                         ty.span,
1622                                         format!("private type in public interface"),
1623                                     );
1624                                 }
1625                             }
1626                             self.is_public = false;
1627                         }
1628                     }
1629                 }
1630                 _ => {}
1631             }
1632         }
1633
1634         intravisit::walk_ty(self, ty);
1635     }
1636
1637     fn visit_trait_ref(&mut self, trait_ref: &hir::TraitRef) {
1638         if self.is_quiet && !self.is_public {
1639             // We are in quiet mode and a private type is already found, no need to proceed
1640             return
1641         }
1642         // Non-local means public (private items can't leave their crate, modulo bugs)
1643         let def_id = self.tcx.trait_ref_to_def_id(trait_ref);
1644         if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
1645             let item = self.tcx.map.expect_item(node_id);
1646             if item.vis != hir::Public {
1647                 if !self.is_quiet {
1648                     if self.old_error_set.contains(&trait_ref.ref_id) {
1649                         span_err!(self.tcx.sess, trait_ref.path.span, E0445,
1650                                   "private trait in public interface");
1651                     } else {
1652                         self.tcx.sess.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
1653                                                node_id,
1654                                                trait_ref.path.span,
1655                                                "private trait in public interface (error E0445)"
1656                                                     .to_string());
1657                     }
1658                 }
1659                 self.is_public = false;
1660             }
1661         }
1662
1663         intravisit::walk_trait_ref(self, trait_ref);
1664     }
1665
1666     // Don't recurse into function bodies
1667     fn visit_block(&mut self, _: &hir::Block) {}
1668     // Don't recurse into expressions in array sizes or const initializers
1669     fn visit_expr(&mut self, _: &hir::Expr) {}
1670     // Don't recurse into patterns in function arguments
1671     fn visit_pat(&mut self, _: &hir::Pat) {}
1672 }
1673
1674 struct PrivateItemsInPublicInterfacesVisitor<'a, 'tcx: 'a> {
1675     tcx: &'a ty::ctxt<'tcx>,
1676     old_error_set: &'a NodeSet,
1677 }
1678
1679 impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
1680     // A type is considered public if it doesn't contain any private components
1681     fn is_public_ty(&self, ty: &hir::Ty) -> bool {
1682         let mut check = SearchInterfaceForPrivateItemsVisitor {
1683             tcx: self.tcx, is_quiet: true, is_public: true, old_error_set: self.old_error_set
1684         };
1685         check.visit_ty(ty);
1686         check.is_public
1687     }
1688
1689     // A trait reference is considered public if it doesn't contain any private components
1690     fn is_public_trait_ref(&self, trait_ref: &hir::TraitRef) -> bool {
1691         let mut check = SearchInterfaceForPrivateItemsVisitor {
1692             tcx: self.tcx, is_quiet: true, is_public: true, old_error_set: self.old_error_set
1693         };
1694         check.visit_trait_ref(trait_ref);
1695         check.is_public
1696     }
1697 }
1698
1699 impl<'a, 'tcx, 'v> Visitor<'v> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
1700     fn visit_item(&mut self, item: &hir::Item) {
1701         let mut check = SearchInterfaceForPrivateItemsVisitor {
1702             tcx: self.tcx, is_quiet: false, is_public: true, old_error_set: self.old_error_set
1703         };
1704         match item.node {
1705             // Crates are always public
1706             hir::ItemExternCrate(..) => {}
1707             // All nested items are checked by visit_item
1708             hir::ItemMod(..) => {}
1709             // Checked in resolve
1710             hir::ItemUse(..) => {}
1711             // Subitems of these items have inherited publicity
1712             hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) |
1713             hir::ItemEnum(..) | hir::ItemTrait(..) | hir::ItemTy(..) => {
1714                 if item.vis == hir::Public {
1715                     check.visit_item(item);
1716                 }
1717             }
1718             // Subitems of foreign modules have their own publicity
1719             hir::ItemForeignMod(ref foreign_mod) => {
1720                 for foreign_item in &foreign_mod.items {
1721                     if foreign_item.vis == hir::Public {
1722                         check.visit_foreign_item(foreign_item);
1723                     }
1724                 }
1725             }
1726             // Subitems of structs have their own publicity
1727             hir::ItemStruct(ref struct_def, ref generics) => {
1728                 if item.vis == hir::Public {
1729                     check.visit_generics(generics);
1730                     for field in struct_def.fields() {
1731                         if field.node.kind.visibility() == hir::Public {
1732                             check.visit_struct_field(field);
1733                         }
1734                     }
1735                 }
1736             }
1737             // The interface is empty
1738             hir::ItemDefaultImpl(..) => {}
1739             // An inherent impl is public when its type is public
1740             // Subitems of inherent impls have their own publicity
1741             hir::ItemImpl(_, _, ref generics, None, ref ty, ref impl_items) => {
1742                 if self.is_public_ty(ty) {
1743                     check.visit_generics(generics);
1744                     for impl_item in impl_items {
1745                         if impl_item.vis == hir::Public {
1746                             check.visit_impl_item(impl_item);
1747                         }
1748                     }
1749                 }
1750             }
1751             // A trait impl is public when both its type and its trait are public
1752             // Subitems of trait impls have inherited publicity
1753             hir::ItemImpl(_, _, ref generics, Some(ref trait_ref), ref ty, ref impl_items) => {
1754                 if self.is_public_ty(ty) && self.is_public_trait_ref(trait_ref) {
1755                     check.visit_generics(generics);
1756                     for impl_item in impl_items {
1757                         check.visit_impl_item(impl_item);
1758                     }
1759                 }
1760             }
1761         }
1762     }
1763 }
1764
1765 pub fn check_crate(tcx: &ty::ctxt,
1766                    export_map: &def::ExportMap,
1767                    external_exports: ExternalExports)
1768                    -> AccessLevels {
1769     let _task = tcx.dep_graph.in_task(DepNode::Privacy);
1770
1771     let krate = tcx.map.krate();
1772
1773     // Sanity check to make sure that all privacy usage is reasonable.
1774     let mut visitor = SanePrivacyVisitor { tcx: tcx };
1775     krate.visit_all_items(&mut visitor);
1776
1777     // Figure out who everyone's parent is
1778     let mut visitor = ParentVisitor {
1779         tcx: tcx,
1780         parents: NodeMap(),
1781         curparent: ast::DUMMY_NODE_ID,
1782     };
1783     intravisit::walk_crate(&mut visitor, krate);
1784
1785     // Use the parent map to check the privacy of everything
1786     let mut visitor = PrivacyVisitor {
1787         curitem: ast::DUMMY_NODE_ID,
1788         in_foreign: false,
1789         tcx: tcx,
1790         parents: visitor.parents,
1791         external_exports: external_exports,
1792     };
1793     intravisit::walk_crate(&mut visitor, krate);
1794
1795     tcx.sess.abort_if_errors();
1796
1797     // Build up a set of all exported items in the AST. This is a set of all
1798     // items which are reachable from external crates based on visibility.
1799     let mut visitor = EmbargoVisitor {
1800         tcx: tcx,
1801         export_map: export_map,
1802         access_levels: Default::default(),
1803         prev_level: Some(AccessLevel::Public),
1804         changed: false,
1805     };
1806     loop {
1807         intravisit::walk_crate(&mut visitor, krate);
1808         if visitor.changed {
1809             visitor.changed = false;
1810         } else {
1811             break
1812         }
1813     }
1814     visitor.update(ast::CRATE_NODE_ID, Some(AccessLevel::Public));
1815
1816     {
1817         let mut visitor = ObsoleteVisiblePrivateTypesVisitor {
1818             tcx: tcx,
1819             access_levels: &visitor.access_levels,
1820             in_variant: false,
1821             old_error_set: NodeSet(),
1822         };
1823         intravisit::walk_crate(&mut visitor, krate);
1824
1825         // Check for private types and traits in public interfaces
1826         let mut visitor = PrivateItemsInPublicInterfacesVisitor {
1827             tcx: tcx,
1828             old_error_set: &visitor.old_error_set,
1829         };
1830         krate.visit_all_items(&mut visitor);
1831     }
1832
1833     visitor.access_levels
1834 }
1835
1836 __build_diagnostic_array! { librustc_privacy, DIAGNOSTICS }