#[macro_use] extern crate syntax;
extern crate syntax_pos;
-use rustc::dep_graph::DepNode;
use rustc::hir::{self, PatKind};
-use rustc::hir::def::{self, Def};
-use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
+use rustc::hir::def::Def;
+use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, CrateNum, DefId};
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use rustc::hir::itemlikevisit::DeepVisitor;
use rustc::hir::pat_util::EnumerateAndAdjustIterator;
use rustc::middle::privacy::{AccessLevel, AccessLevels};
use rustc::ty::{self, TyCtxt, Ty, TypeFoldable};
use rustc::ty::fold::TypeVisitor;
+use rustc::ty::maps::Providers;
use rustc::util::nodemap::NodeSet;
use syntax::ast;
-use syntax_pos::Span;
+use syntax_pos::{DUMMY_SP, Span};
use std::cmp;
use std::mem::replace;
+use std::rc::Rc;
pub mod diagnostics;
+////////////////////////////////////////////////////////////////////////////////
+/// Visitor used to determine if pub(restricted) is used anywhere in the crate.
+///
+/// This is done so that `private_in_public` warnings can be turned into hard errors
+/// in crates that have been updated to use pub(restricted).
+////////////////////////////////////////////////////////////////////////////////
+struct PubRestrictedVisitor<'a, 'tcx: 'a> {
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ has_pub_restricted: bool,
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for PubRestrictedVisitor<'a, 'tcx> {
+ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+ NestedVisitorMap::All(&self.tcx.hir)
+ }
+ fn visit_vis(&mut self, vis: &'tcx hir::Visibility) {
+ self.has_pub_restricted = self.has_pub_restricted || vis.is_pub_restricted();
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
/// The embargo visitor, used to determine the exports of the ast
////////////////////////////////////////////////////////////////////////////////
struct EmbargoVisitor<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
- export_map: &'a def::ExportMap,
// Accessibility levels for reachable nodes
access_levels: AccessLevels,
self.prev_level
}
// Other `pub` items inherit levels from parents
- _ => {
+ hir::ItemConst(..) | hir::ItemEnum(..) | hir::ItemExternCrate(..) |
+ hir::ItemGlobalAsm(..) | hir::ItemFn(..) | hir::ItemMod(..) |
+ hir::ItemStatic(..) | hir::ItemStruct(..) | hir::ItemTrait(..) |
+ hir::ItemTy(..) | hir::ItemUnion(..) | hir::ItemUse(..) => {
if item.vis == hir::Public { self.prev_level } else { None }
}
};
}
}
}
- _ => {}
+ hir::ItemUse(..) | hir::ItemStatic(..) | hir::ItemConst(..) |
+ hir::ItemGlobalAsm(..) | hir::ItemTy(..) | hir::ItemMod(..) |
+ hir::ItemFn(..) | hir::ItemExternCrate(..) | hir::ItemDefaultImpl(..) => {}
}
// Mark all items in interfaces of reachable items as reachable
hir::ItemUse(..) => {}
// The interface is empty
hir::ItemDefaultImpl(..) => {}
+ // The interface is empty
+ hir::ItemGlobalAsm(..) => {}
// Visit everything
hir::ItemConst(..) | hir::ItemStatic(..) |
hir::ItemFn(..) | hir::ItemTy(..) => {
// This code is here instead of in visit_item so that the
// crate module gets processed as well.
if self.prev_level.is_some() {
- if let Some(exports) = self.export_map.get(&id) {
+ if let Some(exports) = self.tcx.export_map.get(&id) {
for export in exports {
if let Some(node_id) = self.tcx.hir.as_local_node_id(export.def.def_id()) {
self.update(node_id, Some(AccessLevel::Exported));
required_visibility: ty::Visibility,
/// The visibility of the least visible component that has been visited
min_visibility: ty::Visibility,
+ has_pub_restricted: bool,
has_old_errors: bool,
}
self.min_visibility = vis;
}
if !vis.is_at_least(self.required_visibility, self.tcx) {
- if self.tcx.sess.features.borrow().pub_restricted || self.has_old_errors {
+ if self.has_pub_restricted || self.has_old_errors {
let mut err = struct_span_err!(self.tcx.sess, self.span, E0446,
"private type `{}` in public interface", ty);
err.span_label(self.span, &format!("can't leak private type"));
self.min_visibility = vis;
}
if !vis.is_at_least(self.required_visibility, self.tcx) {
- if self.tcx.sess.features.borrow().pub_restricted || self.has_old_errors {
+ if self.has_pub_restricted || self.has_old_errors {
struct_span_err!(self.tcx.sess, self.span, E0445,
"private trait `{}` in public interface", trait_ref)
.span_label(self.span, &format!(
struct PrivateItemsInPublicInterfacesVisitor<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ has_pub_restricted: bool,
old_error_set: &'a NodeSet,
inner_visibility: ty::Visibility,
}
span: self.tcx.hir.span(item_id),
min_visibility: ty::Visibility::Public,
required_visibility: required_visibility,
+ has_pub_restricted: self.has_pub_restricted,
has_old_errors: has_old_errors,
}
}
hir::ItemMod(..) => {}
// Checked in resolve
hir::ItemUse(..) => {}
+ // No subitems
+ hir::ItemGlobalAsm(..) => {}
// Subitems of these items have inherited publicity
hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) |
hir::ItemTy(..) => {
fn visit_pat(&mut self, _: &'tcx hir::Pat) {}
}
-pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- export_map: &def::ExportMap)
- -> AccessLevels {
- let _task = tcx.dep_graph.in_task(DepNode::Privacy);
+pub fn provide(providers: &mut Providers) {
+ *providers = Providers {
+ privacy_access_levels,
+ ..*providers
+ };
+}
+
+pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Rc<AccessLevels> {
+ tcx.dep_graph.with_ignore(|| { // FIXME
+ ty::queries::privacy_access_levels::get(tcx, DUMMY_SP, LOCAL_CRATE)
+ })
+}
+
+fn privacy_access_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ krate: CrateNum)
+ -> Rc<AccessLevels> {
+ assert_eq!(krate, LOCAL_CRATE);
let krate = tcx.hir.krate();
// items which are reachable from external crates based on visibility.
let mut visitor = EmbargoVisitor {
tcx: tcx,
- export_map: export_map,
access_levels: Default::default(),
prev_level: Some(AccessLevel::Public),
changed: false,
};
intravisit::walk_crate(&mut visitor, krate);
+
+ let has_pub_restricted = {
+ let mut pub_restricted_visitor = PubRestrictedVisitor {
+ tcx: tcx,
+ has_pub_restricted: false
+ };
+ intravisit::walk_crate(&mut pub_restricted_visitor, krate);
+ pub_restricted_visitor.has_pub_restricted
+ };
+
// Check for private types and traits in public interfaces
let mut visitor = PrivateItemsInPublicInterfacesVisitor {
tcx: tcx,
+ has_pub_restricted: has_pub_restricted,
old_error_set: &visitor.old_error_set,
inner_visibility: ty::Visibility::Public,
};
krate.visit_all_item_likes(&mut DeepVisitor::new(&mut visitor));
}
- visitor.access_levels
+ Rc::new(visitor.access_levels)
}
__build_diagnostic_array! { librustc_privacy, DIAGNOSTICS }