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