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