]> git.lizzy.rs Git - rust.git/blob - src/librustc_privacy/lib.rs
Permit `pub` items in blocks
[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     /// Validates all of the visibility qualifiers placed on the item given. This
1143     /// ensures that there are no extraneous qualifiers that don't actually do
1144     /// anything. In theory these qualifiers wouldn't parse, but that may happen
1145     /// later on down the road...
1146     fn check_sane_privacy(&self, item: &hir::Item) {
1147         let check_inherited = |sp, vis, note: &str| {
1148             if vis != hir::Inherited {
1149                 let mut err = struct_span_err!(self.tcx.sess, sp, E0449,
1150                                                "unnecessary visibility qualifier");
1151                 if !note.is_empty() {
1152                     err.span_note(sp, note);
1153                 }
1154                 err.emit();
1155             }
1156         };
1157
1158         match item.node {
1159             // implementations of traits don't need visibility qualifiers because
1160             // that's controlled by having the trait in scope.
1161             hir::ItemImpl(_, _, _, Some(..), _, ref impl_items) => {
1162                 check_inherited(item.span, item.vis,
1163                                 "visibility qualifiers have no effect on trait impls");
1164                 for impl_item in impl_items {
1165                     check_inherited(impl_item.span, impl_item.vis, "");
1166                 }
1167             }
1168             hir::ItemImpl(_, _, _, None, _, _) => {
1169                 check_inherited(item.span, item.vis,
1170                                 "place qualifiers on individual methods instead");
1171             }
1172             hir::ItemDefaultImpl(..) => {
1173                 check_inherited(item.span, item.vis,
1174                                 "visibility qualifiers have no effect on trait impls");
1175             }
1176             hir::ItemForeignMod(..) => {
1177                 check_inherited(item.span, item.vis,
1178                                 "place qualifiers on individual functions instead");
1179             }
1180             hir::ItemStruct(..) | hir::ItemEnum(..) | hir::ItemTrait(..) |
1181             hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) |
1182             hir::ItemMod(..) | hir::ItemExternCrate(..) |
1183             hir::ItemUse(..) | hir::ItemTy(..) => {}
1184         }
1185     }
1186 }
1187
1188 ///////////////////////////////////////////////////////////////////////////////
1189 /// Obsolete visitors for checking for private items in public interfaces.
1190 /// These visitors are supposed to be kept in frozen state and produce an
1191 /// "old error node set". For backward compatibility the new visitor reports
1192 /// warnings instead of hard errors when the erroneous node is not in this old set.
1193 ///////////////////////////////////////////////////////////////////////////////
1194
1195 struct ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx: 'a> {
1196     tcx: &'a ty::ctxt<'tcx>,
1197     access_levels: &'a AccessLevels,
1198     in_variant: bool,
1199     // set of errors produced by this obsolete visitor
1200     old_error_set: NodeSet,
1201 }
1202
1203 struct ObsoleteCheckTypeForPrivatenessVisitor<'a, 'b: 'a, 'tcx: 'b> {
1204     inner: &'a ObsoleteVisiblePrivateTypesVisitor<'b, 'tcx>,
1205     /// whether the type refers to private types.
1206     contains_private: bool,
1207     /// whether we've recurred at all (i.e. if we're pointing at the
1208     /// first type on which visit_ty was called).
1209     at_outer_type: bool,
1210     // whether that first type is a public path.
1211     outer_type_is_public_path: bool,
1212 }
1213
1214 impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
1215     fn path_is_private_type(&self, path_id: ast::NodeId) -> bool {
1216         let did = match self.tcx.def_map.borrow().get(&path_id).map(|d| d.full_def()) {
1217             // `int` etc. (None doesn't seem to occur.)
1218             None | Some(Def::PrimTy(..)) | Some(Def::SelfTy(..)) => return false,
1219             Some(def) => def.def_id(),
1220         };
1221
1222         // A path can only be private if:
1223         // it's in this crate...
1224         if let Some(node_id) = self.tcx.map.as_local_node_id(did) {
1225             // .. and it corresponds to a private type in the AST (this returns
1226             // None for type parameters)
1227             match self.tcx.map.find(node_id) {
1228                 Some(ast_map::NodeItem(ref item)) => item.vis != hir::Public,
1229                 Some(_) | None => false,
1230             }
1231         } else {
1232             return false
1233         }
1234     }
1235
1236     fn trait_is_public(&self, trait_id: ast::NodeId) -> bool {
1237         // FIXME: this would preferably be using `exported_items`, but all
1238         // traits are exported currently (see `EmbargoVisitor.exported_trait`)
1239         self.access_levels.is_public(trait_id)
1240     }
1241
1242     fn check_ty_param_bound(&mut self,
1243                             ty_param_bound: &hir::TyParamBound) {
1244         if let hir::TraitTyParamBound(ref trait_ref, _) = *ty_param_bound {
1245             if self.path_is_private_type(trait_ref.trait_ref.ref_id) {
1246                 self.old_error_set.insert(trait_ref.trait_ref.ref_id);
1247             }
1248         }
1249     }
1250
1251     fn item_is_public(&self, id: &ast::NodeId, vis: hir::Visibility) -> bool {
1252         self.access_levels.is_reachable(*id) || vis == hir::Public
1253     }
1254 }
1255
1256 impl<'a, 'b, 'tcx, 'v> Visitor<'v> for ObsoleteCheckTypeForPrivatenessVisitor<'a, 'b, 'tcx> {
1257     fn visit_ty(&mut self, ty: &hir::Ty) {
1258         if let hir::TyPath(..) = ty.node {
1259             if self.inner.path_is_private_type(ty.id) {
1260                 self.contains_private = true;
1261                 // found what we're looking for so let's stop
1262                 // working.
1263                 return
1264             } else if self.at_outer_type {
1265                 self.outer_type_is_public_path = true;
1266             }
1267         }
1268         self.at_outer_type = false;
1269         intravisit::walk_ty(self, ty)
1270     }
1271
1272     // don't want to recurse into [, .. expr]
1273     fn visit_expr(&mut self, _: &hir::Expr) {}
1274 }
1275
1276 impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
1277     /// We want to visit items in the context of their containing
1278     /// module and so forth, so supply a crate for doing a deep walk.
1279     fn visit_nested_item(&mut self, item: hir::ItemId) {
1280         self.visit_item(self.tcx.map.expect_item(item.id))
1281     }
1282
1283     fn visit_item(&mut self, item: &hir::Item) {
1284         match item.node {
1285             // contents of a private mod can be reexported, so we need
1286             // to check internals.
1287             hir::ItemMod(_) => {}
1288
1289             // An `extern {}` doesn't introduce a new privacy
1290             // namespace (the contents have their own privacies).
1291             hir::ItemForeignMod(_) => {}
1292
1293             hir::ItemTrait(_, _, ref bounds, _) => {
1294                 if !self.trait_is_public(item.id) {
1295                     return
1296                 }
1297
1298                 for bound in bounds.iter() {
1299                     self.check_ty_param_bound(bound)
1300                 }
1301             }
1302
1303             // impls need some special handling to try to offer useful
1304             // error messages without (too many) false positives
1305             // (i.e. we could just return here to not check them at
1306             // all, or some worse estimation of whether an impl is
1307             // publicly visible).
1308             hir::ItemImpl(_, _, ref g, ref trait_ref, ref self_, ref impl_items) => {
1309                 // `impl [... for] Private` is never visible.
1310                 let self_contains_private;
1311                 // impl [... for] Public<...>, but not `impl [... for]
1312                 // Vec<Public>` or `(Public,)` etc.
1313                 let self_is_public_path;
1314
1315                 // check the properties of the Self type:
1316                 {
1317                     let mut visitor = ObsoleteCheckTypeForPrivatenessVisitor {
1318                         inner: self,
1319                         contains_private: false,
1320                         at_outer_type: true,
1321                         outer_type_is_public_path: false,
1322                     };
1323                     visitor.visit_ty(&self_);
1324                     self_contains_private = visitor.contains_private;
1325                     self_is_public_path = visitor.outer_type_is_public_path;
1326                 }
1327
1328                 // miscellaneous info about the impl
1329
1330                 // `true` iff this is `impl Private for ...`.
1331                 let not_private_trait =
1332                     trait_ref.as_ref().map_or(true, // no trait counts as public trait
1333                                               |tr| {
1334                         let did = self.tcx.trait_ref_to_def_id(tr);
1335
1336                         if let Some(node_id) = self.tcx.map.as_local_node_id(did) {
1337                             self.trait_is_public(node_id)
1338                         } else {
1339                             true // external traits must be public
1340                         }
1341                     });
1342
1343                 // `true` iff this is a trait impl or at least one method is public.
1344                 //
1345                 // `impl Public { $( fn ...() {} )* }` is not visible.
1346                 //
1347                 // This is required over just using the methods' privacy
1348                 // directly because we might have `impl<T: Foo<Private>> ...`,
1349                 // and we shouldn't warn about the generics if all the methods
1350                 // are private (because `T` won't be visible externally).
1351                 let trait_or_some_public_method =
1352                     trait_ref.is_some() ||
1353                     impl_items.iter()
1354                               .any(|impl_item| {
1355                                   match impl_item.node {
1356                                       hir::ImplItemKind::Const(..) |
1357                                       hir::ImplItemKind::Method(..) => {
1358                                           self.access_levels.is_reachable(impl_item.id)
1359                                       }
1360                                       hir::ImplItemKind::Type(_) => false,
1361                                   }
1362                               });
1363
1364                 if !self_contains_private &&
1365                         not_private_trait &&
1366                         trait_or_some_public_method {
1367
1368                     intravisit::walk_generics(self, g);
1369
1370                     match *trait_ref {
1371                         None => {
1372                             for impl_item in impl_items {
1373                                 // This is where we choose whether to walk down
1374                                 // further into the impl to check its items. We
1375                                 // should only walk into public items so that we
1376                                 // don't erroneously report errors for private
1377                                 // types in private items.
1378                                 match impl_item.node {
1379                                     hir::ImplItemKind::Const(..) |
1380                                     hir::ImplItemKind::Method(..)
1381                                         if self.item_is_public(&impl_item.id, impl_item.vis) =>
1382                                     {
1383                                         intravisit::walk_impl_item(self, impl_item)
1384                                     }
1385                                     hir::ImplItemKind::Type(..) => {
1386                                         intravisit::walk_impl_item(self, impl_item)
1387                                     }
1388                                     _ => {}
1389                                 }
1390                             }
1391                         }
1392                         Some(ref tr) => {
1393                             // Any private types in a trait impl fall into three
1394                             // categories.
1395                             // 1. mentioned in the trait definition
1396                             // 2. mentioned in the type params/generics
1397                             // 3. mentioned in the associated types of the impl
1398                             //
1399                             // Those in 1. can only occur if the trait is in
1400                             // this crate and will've been warned about on the
1401                             // trait definition (there's no need to warn twice
1402                             // so we don't check the methods).
1403                             //
1404                             // Those in 2. are warned via walk_generics and this
1405                             // call here.
1406                             intravisit::walk_path(self, &tr.path);
1407
1408                             // Those in 3. are warned with this call.
1409                             for impl_item in impl_items {
1410                                 if let hir::ImplItemKind::Type(ref ty) = impl_item.node {
1411                                     self.visit_ty(ty);
1412                                 }
1413                             }
1414                         }
1415                     }
1416                 } else if trait_ref.is_none() && self_is_public_path {
1417                     // impl Public<Private> { ... }. Any public static
1418                     // methods will be visible as `Public::foo`.
1419                     let mut found_pub_static = false;
1420                     for impl_item in impl_items {
1421                         match impl_item.node {
1422                             hir::ImplItemKind::Const(..) => {
1423                                 if self.item_is_public(&impl_item.id, impl_item.vis) {
1424                                     found_pub_static = true;
1425                                     intravisit::walk_impl_item(self, impl_item);
1426                                 }
1427                             }
1428                             hir::ImplItemKind::Method(ref sig, _) => {
1429                                 if sig.explicit_self.node == hir::SelfStatic &&
1430                                       self.item_is_public(&impl_item.id, impl_item.vis) {
1431                                     found_pub_static = true;
1432                                     intravisit::walk_impl_item(self, impl_item);
1433                                 }
1434                             }
1435                             _ => {}
1436                         }
1437                     }
1438                     if found_pub_static {
1439                         intravisit::walk_generics(self, g)
1440                     }
1441                 }
1442                 return
1443             }
1444
1445             // `type ... = ...;` can contain private types, because
1446             // we're introducing a new name.
1447             hir::ItemTy(..) => return,
1448
1449             // not at all public, so we don't care
1450             _ if !self.item_is_public(&item.id, item.vis) => {
1451                 return;
1452             }
1453
1454             _ => {}
1455         }
1456
1457         // We've carefully constructed it so that if we're here, then
1458         // any `visit_ty`'s will be called on things that are in
1459         // public signatures, i.e. things that we're interested in for
1460         // this visitor.
1461         debug!("VisiblePrivateTypesVisitor entering item {:?}", item);
1462         intravisit::walk_item(self, item);
1463     }
1464
1465     fn visit_generics(&mut self, generics: &hir::Generics) {
1466         for ty_param in generics.ty_params.iter() {
1467             for bound in ty_param.bounds.iter() {
1468                 self.check_ty_param_bound(bound)
1469             }
1470         }
1471         for predicate in &generics.where_clause.predicates {
1472             match predicate {
1473                 &hir::WherePredicate::BoundPredicate(ref bound_pred) => {
1474                     for bound in bound_pred.bounds.iter() {
1475                         self.check_ty_param_bound(bound)
1476                     }
1477                 }
1478                 &hir::WherePredicate::RegionPredicate(_) => {}
1479                 &hir::WherePredicate::EqPredicate(ref eq_pred) => {
1480                     self.visit_ty(&eq_pred.ty);
1481                 }
1482             }
1483         }
1484     }
1485
1486     fn visit_foreign_item(&mut self, item: &hir::ForeignItem) {
1487         if self.access_levels.is_reachable(item.id) {
1488             intravisit::walk_foreign_item(self, item)
1489         }
1490     }
1491
1492     fn visit_ty(&mut self, t: &hir::Ty) {
1493         debug!("VisiblePrivateTypesVisitor checking ty {:?}", t);
1494         if let hir::TyPath(..) = t.node {
1495             if self.path_is_private_type(t.id) {
1496                 self.old_error_set.insert(t.id);
1497             }
1498         }
1499         intravisit::walk_ty(self, t)
1500     }
1501
1502     fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics, item_id: ast::NodeId) {
1503         if self.access_levels.is_reachable(v.node.data.id()) {
1504             self.in_variant = true;
1505             intravisit::walk_variant(self, v, g, item_id);
1506             self.in_variant = false;
1507         }
1508     }
1509
1510     fn visit_struct_field(&mut self, s: &hir::StructField) {
1511         let vis = match s.node.kind {
1512             hir::NamedField(_, vis) | hir::UnnamedField(vis) => vis
1513         };
1514         if vis == hir::Public || self.in_variant {
1515             intravisit::walk_struct_field(self, s);
1516         }
1517     }
1518
1519     // we don't need to introspect into these at all: an
1520     // expression/block context can't possibly contain exported things.
1521     // (Making them no-ops stops us from traversing the whole AST without
1522     // having to be super careful about our `walk_...` calls above.)
1523     // FIXME(#29524): Unfortunately this ^^^ is not true, blocks can contain
1524     // exported items (e.g. impls) and actual code in rustc itself breaks
1525     // if we don't traverse blocks in `EmbargoVisitor`
1526     fn visit_block(&mut self, _: &hir::Block) {}
1527     fn visit_expr(&mut self, _: &hir::Expr) {}
1528 }
1529
1530 ///////////////////////////////////////////////////////////////////////////////
1531 /// SearchInterfaceForPrivateItemsVisitor traverses an item's interface and
1532 /// finds any private components in it.
1533 /// PrivateItemsInPublicInterfacesVisitor ensures there are no private types
1534 /// and traits in public interfaces.
1535 ///////////////////////////////////////////////////////////////////////////////
1536
1537 struct SearchInterfaceForPrivateItemsVisitor<'a, 'tcx: 'a> {
1538     tcx: &'a ty::ctxt<'tcx>,
1539     // Do not report an error when a private type is found
1540     is_quiet: bool,
1541     // Is private component found?
1542     is_public: bool,
1543     old_error_set: &'a NodeSet,
1544 }
1545
1546 impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
1547     // Check if the type alias contain private types when substituted
1548     fn is_public_type_alias(&self, item: &hir::Item, path: &hir::Path) -> bool {
1549         // We substitute type aliases only when determining impl publicity
1550         // FIXME: This will probably change and all type aliases will be substituted,
1551         // requires an amendment to RFC 136.
1552         if !self.is_quiet {
1553             return false
1554         }
1555         // Type alias is considered public if the aliased type is
1556         // public, even if the type alias itself is private. So, something
1557         // like `type A = u8; pub fn f() -> A {...}` doesn't cause an error.
1558         if let hir::ItemTy(ref ty, ref generics) = item.node {
1559             let mut check = SearchInterfaceForPrivateItemsVisitor { is_public: true, ..*self };
1560             check.visit_ty(ty);
1561             // If a private type alias with default type parameters is used in public
1562             // interface we must ensure, that the defaults are public if they are actually used.
1563             // ```
1564             // type Alias<T = Private> = T;
1565             // pub fn f() -> Alias {...} // `Private` is implicitly used here, so it must be public
1566             // ```
1567             let provided_params = path.segments.last().unwrap().parameters.types().len();
1568             for ty_param in &generics.ty_params[provided_params..] {
1569                 if let Some(ref default_ty) = ty_param.default {
1570                     check.visit_ty(default_ty);
1571                 }
1572             }
1573             check.is_public
1574         } else {
1575             false
1576         }
1577     }
1578 }
1579
1580 impl<'a, 'tcx: 'a, 'v> Visitor<'v> for SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
1581     fn visit_ty(&mut self, ty: &hir::Ty) {
1582         if self.is_quiet && !self.is_public {
1583             // We are in quiet mode and a private type is already found, no need to proceed
1584             return
1585         }
1586         if let hir::TyPath(_, ref path) = ty.node {
1587             let def = self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def();
1588             match def {
1589                 Def::PrimTy(..) | Def::SelfTy(..) | Def::TyParam(..) => {
1590                     // Public
1591                 }
1592                 Def::AssociatedTy(..) if self.is_quiet => {
1593                     // Conservatively approximate the whole type alias as public without
1594                     // recursing into its components when determining impl publicity.
1595                     // For example, `impl <Type as Trait>::Alias {...}` may be a public impl
1596                     // even if both `Type` and `Trait` are private.
1597                     // Ideally, associated types should be substituted in the same way as
1598                     // free type aliases, but this isn't done yet.
1599                     return
1600                 }
1601                 Def::Struct(def_id) | Def::Enum(def_id) | Def::TyAlias(def_id) |
1602                 Def::Trait(def_id) | Def::AssociatedTy(def_id, _) => {
1603                     // Non-local means public (private items can't leave their crate, modulo bugs)
1604                     if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
1605                         let item = self.tcx.map.expect_item(node_id);
1606                         if item.vis != hir::Public && !self.is_public_type_alias(item, path) {
1607                             if !self.is_quiet {
1608                                 if self.old_error_set.contains(&ty.id) {
1609                                     span_err!(self.tcx.sess, ty.span, E0446,
1610                                               "private type in public interface");
1611                                 } else {
1612                                     self.tcx.sess.add_lint (
1613                                         lint::builtin::PRIVATE_IN_PUBLIC,
1614                                         node_id,
1615                                         ty.span,
1616                                         format!("private type in public interface"),
1617                                     );
1618                                 }
1619                             }
1620                             self.is_public = false;
1621                         }
1622                     }
1623                 }
1624                 _ => {}
1625             }
1626         }
1627
1628         intravisit::walk_ty(self, ty);
1629     }
1630
1631     fn visit_trait_ref(&mut self, trait_ref: &hir::TraitRef) {
1632         if self.is_quiet && !self.is_public {
1633             // We are in quiet mode and a private type is already found, no need to proceed
1634             return
1635         }
1636         // Non-local means public (private items can't leave their crate, modulo bugs)
1637         let def_id = self.tcx.trait_ref_to_def_id(trait_ref);
1638         if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
1639             let item = self.tcx.map.expect_item(node_id);
1640             if item.vis != hir::Public {
1641                 if !self.is_quiet {
1642                     if self.old_error_set.contains(&trait_ref.ref_id) {
1643                         span_err!(self.tcx.sess, trait_ref.path.span, E0445,
1644                                   "private trait in public interface");
1645                     } else {
1646                         self.tcx.sess.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
1647                                                node_id,
1648                                                trait_ref.path.span,
1649                                                "private trait in public interface (error E0445)"
1650                                                     .to_string());
1651                     }
1652                 }
1653                 self.is_public = false;
1654             }
1655         }
1656
1657         intravisit::walk_trait_ref(self, trait_ref);
1658     }
1659
1660     // Don't recurse into function bodies
1661     fn visit_block(&mut self, _: &hir::Block) {}
1662     // Don't recurse into expressions in array sizes or const initializers
1663     fn visit_expr(&mut self, _: &hir::Expr) {}
1664     // Don't recurse into patterns in function arguments
1665     fn visit_pat(&mut self, _: &hir::Pat) {}
1666 }
1667
1668 struct PrivateItemsInPublicInterfacesVisitor<'a, 'tcx: 'a> {
1669     tcx: &'a ty::ctxt<'tcx>,
1670     old_error_set: &'a NodeSet,
1671 }
1672
1673 impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
1674     // A type is considered public if it doesn't contain any private components
1675     fn is_public_ty(&self, ty: &hir::Ty) -> bool {
1676         let mut check = SearchInterfaceForPrivateItemsVisitor {
1677             tcx: self.tcx, is_quiet: true, is_public: true, old_error_set: self.old_error_set
1678         };
1679         check.visit_ty(ty);
1680         check.is_public
1681     }
1682
1683     // A trait reference is considered public if it doesn't contain any private components
1684     fn is_public_trait_ref(&self, trait_ref: &hir::TraitRef) -> bool {
1685         let mut check = SearchInterfaceForPrivateItemsVisitor {
1686             tcx: self.tcx, is_quiet: true, is_public: true, old_error_set: self.old_error_set
1687         };
1688         check.visit_trait_ref(trait_ref);
1689         check.is_public
1690     }
1691 }
1692
1693 impl<'a, 'tcx, 'v> Visitor<'v> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
1694     fn visit_item(&mut self, item: &hir::Item) {
1695         let mut check = SearchInterfaceForPrivateItemsVisitor {
1696             tcx: self.tcx, is_quiet: false, is_public: true, old_error_set: self.old_error_set
1697         };
1698         match item.node {
1699             // Crates are always public
1700             hir::ItemExternCrate(..) => {}
1701             // All nested items are checked by visit_item
1702             hir::ItemMod(..) => {}
1703             // Checked in resolve
1704             hir::ItemUse(..) => {}
1705             // Subitems of these items have inherited publicity
1706             hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) |
1707             hir::ItemEnum(..) | hir::ItemTrait(..) | hir::ItemTy(..) => {
1708                 if item.vis == hir::Public {
1709                     check.visit_item(item);
1710                 }
1711             }
1712             // Subitems of foreign modules have their own publicity
1713             hir::ItemForeignMod(ref foreign_mod) => {
1714                 for foreign_item in &foreign_mod.items {
1715                     if foreign_item.vis == hir::Public {
1716                         check.visit_foreign_item(foreign_item);
1717                     }
1718                 }
1719             }
1720             // Subitems of structs have their own publicity
1721             hir::ItemStruct(ref struct_def, ref generics) => {
1722                 if item.vis == hir::Public {
1723                     check.visit_generics(generics);
1724                     for field in struct_def.fields() {
1725                         if field.node.kind.visibility() == hir::Public {
1726                             check.visit_struct_field(field);
1727                         }
1728                     }
1729                 }
1730             }
1731             // The interface is empty
1732             hir::ItemDefaultImpl(..) => {}
1733             // An inherent impl is public when its type is public
1734             // Subitems of inherent impls have their own publicity
1735             hir::ItemImpl(_, _, ref generics, None, ref ty, ref impl_items) => {
1736                 if self.is_public_ty(ty) {
1737                     check.visit_generics(generics);
1738                     for impl_item in impl_items {
1739                         if impl_item.vis == hir::Public {
1740                             check.visit_impl_item(impl_item);
1741                         }
1742                     }
1743                 }
1744             }
1745             // A trait impl is public when both its type and its trait are public
1746             // Subitems of trait impls have inherited publicity
1747             hir::ItemImpl(_, _, ref generics, Some(ref trait_ref), ref ty, ref impl_items) => {
1748                 if self.is_public_ty(ty) && self.is_public_trait_ref(trait_ref) {
1749                     check.visit_generics(generics);
1750                     for impl_item in impl_items {
1751                         check.visit_impl_item(impl_item);
1752                     }
1753                 }
1754             }
1755         }
1756     }
1757 }
1758
1759 pub fn check_crate(tcx: &ty::ctxt,
1760                    export_map: &def::ExportMap,
1761                    external_exports: ExternalExports)
1762                    -> AccessLevels {
1763     let _task = tcx.dep_graph.in_task(DepNode::Privacy);
1764
1765     let krate = tcx.map.krate();
1766
1767     // Sanity check to make sure that all privacy usage and controls are
1768     // reasonable.
1769     let mut visitor = SanePrivacyVisitor { tcx: tcx };
1770     krate.visit_all_items(&mut visitor);
1771
1772     // Figure out who everyone's parent is
1773     let mut visitor = ParentVisitor {
1774         tcx: tcx,
1775         parents: NodeMap(),
1776         curparent: ast::DUMMY_NODE_ID,
1777     };
1778     intravisit::walk_crate(&mut visitor, krate);
1779
1780     // Use the parent map to check the privacy of everything
1781     let mut visitor = PrivacyVisitor {
1782         curitem: ast::DUMMY_NODE_ID,
1783         in_foreign: false,
1784         tcx: tcx,
1785         parents: visitor.parents,
1786         external_exports: external_exports,
1787     };
1788     intravisit::walk_crate(&mut visitor, krate);
1789
1790     tcx.sess.abort_if_errors();
1791
1792     // Build up a set of all exported items in the AST. This is a set of all
1793     // items which are reachable from external crates based on visibility.
1794     let mut visitor = EmbargoVisitor {
1795         tcx: tcx,
1796         export_map: export_map,
1797         access_levels: Default::default(),
1798         prev_level: Some(AccessLevel::Public),
1799         changed: false,
1800     };
1801     loop {
1802         intravisit::walk_crate(&mut visitor, krate);
1803         if visitor.changed {
1804             visitor.changed = false;
1805         } else {
1806             break
1807         }
1808     }
1809     visitor.update(ast::CRATE_NODE_ID, Some(AccessLevel::Public));
1810
1811     {
1812         let mut visitor = ObsoleteVisiblePrivateTypesVisitor {
1813             tcx: tcx,
1814             access_levels: &visitor.access_levels,
1815             in_variant: false,
1816             old_error_set: NodeSet(),
1817         };
1818         intravisit::walk_crate(&mut visitor, krate);
1819
1820         // Check for private types and traits in public interfaces
1821         let mut visitor = PrivateItemsInPublicInterfacesVisitor {
1822             tcx: tcx,
1823             old_error_set: &visitor.old_error_set,
1824         };
1825         krate.visit_all_items(&mut visitor);
1826     }
1827
1828     visitor.access_levels
1829 }
1830
1831 __build_diagnostic_array! { librustc_privacy, DIAGNOSTICS }