Skip to content

Commit

Permalink
Changes to data produced by privacy pass
Browse files Browse the repository at this point in the history
  • Loading branch information
petrochenkov committed Nov 19, 2015
1 parent 3e48b0e commit c1ad5af
Show file tree
Hide file tree
Showing 13 changed files with 205 additions and 274 deletions.
15 changes: 7 additions & 8 deletions src/librustc/lint/context.rs
Expand Up @@ -25,7 +25,7 @@
//! for all lint attributes.
use self::TargetLint::*;

use middle::privacy::ExportedItems;
use middle::privacy::AccessLevels;
use middle::ty::{self, Ty};
use session::{early_error, Session};
use lint::{Level, LevelSource, Lint, LintId, LintArray, LintPass};
Expand Down Expand Up @@ -277,8 +277,8 @@ pub struct LateContext<'a, 'tcx: 'a> {
/// The crate being checked.
pub krate: &'a hir::Crate,

/// Items exported from the crate being checked.
pub exported_items: &'a ExportedItems,
/// Items accessible from the crate being checked.
pub access_levels: &'a AccessLevels,

/// The store of registered lints.
lints: LintStore,
Expand Down Expand Up @@ -564,15 +564,15 @@ impl<'a> EarlyContext<'a> {
impl<'a, 'tcx> LateContext<'a, 'tcx> {
fn new(tcx: &'a ty::ctxt<'tcx>,
krate: &'a hir::Crate,
exported_items: &'a ExportedItems) -> LateContext<'a, 'tcx> {
access_levels: &'a AccessLevels) -> LateContext<'a, 'tcx> {
// We want to own the lint store, so move it out of the session.
let lint_store = mem::replace(&mut *tcx.sess.lint_store.borrow_mut(),
LintStore::new());

LateContext {
tcx: tcx,
krate: krate,
exported_items: exported_items,
access_levels: access_levels,
lints: lint_store,
level_stack: vec![],
node_levels: RefCell::new(FnvHashMap()),
Expand Down Expand Up @@ -1014,10 +1014,9 @@ impl LateLintPass for GatherNodeLevels {
/// Perform lint checking on a crate.
///
/// Consumes the `lint_store` field of the `Session`.
pub fn check_crate(tcx: &ty::ctxt,
exported_items: &ExportedItems) {
pub fn check_crate(tcx: &ty::ctxt, access_levels: &AccessLevels) {
let krate = tcx.map.krate();
let mut cx = LateContext::new(tcx, krate, exported_items);
let mut cx = LateContext::new(tcx, krate, access_levels);

// Visit the whole crate.
cx.with_lint_attrs(&krate.attrs, |cx| {
Expand Down
33 changes: 6 additions & 27 deletions src/librustc/middle/dead.rs
Expand Up @@ -19,7 +19,6 @@ use rustc_front::intravisit::{self, Visitor};
use middle::{def, pat_util, privacy, ty};
use middle::def_id::{DefId};
use lint;
use util::nodemap::NodeSet;

use std::collections::HashSet;
use syntax::{ast, codemap};
Expand Down Expand Up @@ -370,25 +369,10 @@ impl<'v> Visitor<'v> for LifeSeeder {
}

fn create_and_seed_worklist(tcx: &ty::ctxt,
exported_items: &privacy::ExportedItems,
reachable_symbols: &NodeSet,
access_levels: &privacy::AccessLevels,
krate: &hir::Crate) -> Vec<ast::NodeId> {
let mut worklist = Vec::new();

// Preferably, we would only need to seed the worklist with reachable
// symbols. However, since the set of reachable symbols differs
// depending on whether a crate is built as bin or lib, and we want
// the warning to be consistent, we also seed the worklist with
// exported symbols.
for id in exported_items {
worklist.push(*id);
}
for id in reachable_symbols {
// Reachable variants can be dead, because we warn about
// variants never constructed, not variants never used.
if let Some(ast_map::NodeVariant(..)) = tcx.map.find(*id) {
continue;
}
for (id, _) in &access_levels.map {
worklist.push(*id);
}

Expand All @@ -408,12 +392,10 @@ fn create_and_seed_worklist(tcx: &ty::ctxt,
}

fn find_live(tcx: &ty::ctxt,
exported_items: &privacy::ExportedItems,
reachable_symbols: &NodeSet,
access_levels: &privacy::AccessLevels,
krate: &hir::Crate)
-> Box<HashSet<ast::NodeId>> {
let worklist = create_and_seed_worklist(tcx, exported_items,
reachable_symbols, krate);
let worklist = create_and_seed_worklist(tcx, access_levels, krate);
let mut symbol_visitor = MarkSymbolVisitor::new(tcx, worklist);
symbol_visitor.mark_live_symbols();
symbol_visitor.live_symbols
Expand Down Expand Up @@ -607,12 +589,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
}
}

pub fn check_crate(tcx: &ty::ctxt,
exported_items: &privacy::ExportedItems,
reachable_symbols: &NodeSet) {
pub fn check_crate(tcx: &ty::ctxt, access_levels: &privacy::AccessLevels) {
let krate = tcx.map.krate();
let live_symbols = find_live(tcx, exported_items,
reachable_symbols, krate);
let live_symbols = find_live(tcx, access_levels, krate);
let mut visitor = DeadVisitor { tcx: tcx, live_symbols: live_symbols };
intravisit::walk_crate(&mut visitor, krate);
}
50 changes: 42 additions & 8 deletions src/librustc/middle/privacy.rs
Expand Up @@ -17,20 +17,54 @@ pub use self::ImportUse::*;
pub use self::LastPrivate::*;

use middle::def_id::DefId;
use util::nodemap::{DefIdSet, NodeSet};
use util::nodemap::{DefIdSet, FnvHashMap};

/// A set of AST nodes exported by the crate.
pub type ExportedItems = NodeSet;
use std::hash::Hash;
use syntax::ast::NodeId;

// Accessibility levels, sorted in ascending order
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum AccessLevel {
// Exported items + items participating in various kinds of public interfaces,
// but not directly nameable. For example, if function `fn f() -> T {...}` is
// public, then type `T` is exported. Its values can be obtained by other crates
// even if the type itseld is not nameable.
// FIXME: Mostly unimplemented. Only `type` aliases export items currently.
Reachable,
// Public items + items accessible to other crates with help of `pub use` reexports
Exported,
// Items accessible to other crates directly, without help of reexports
Public,
}

// Accessibility levels for reachable HIR nodes
#[derive(Clone)]
pub struct AccessLevels<Id = NodeId> {
pub map: FnvHashMap<Id, AccessLevel>
}

impl<Id: Hash + Eq> AccessLevels<Id> {
pub fn is_reachable(&self, id: Id) -> bool {
self.map.contains_key(&id)
}
pub fn is_exported(&self, id: Id) -> bool {
self.map.get(&id) >= Some(&AccessLevel::Exported)
}
pub fn is_public(&self, id: Id) -> bool {
self.map.get(&id) >= Some(&AccessLevel::Public)
}
}

impl<Id: Hash + Eq> Default for AccessLevels<Id> {
fn default() -> Self {
AccessLevels { map: Default::default() }
}
}

/// A set containing all exported definitions from external crates.
/// The set does not contain any entries from local crates.
pub type ExternalExports = DefIdSet;

/// A set of AST nodes that are fully public in the crate. This map is used for
/// documentation purposes (reexporting a private struct inlines the doc,
/// reexporting a public struct doesn't inline the doc).
pub type PublicItems = NodeSet;

#[derive(Copy, Clone, Debug)]
pub enum LastPrivate {
LastMod(PrivateDep),
Expand Down
10 changes: 5 additions & 5 deletions src/librustc/middle/reachable.rs
Expand Up @@ -329,15 +329,15 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
// trait items are used from inlinable code through method call syntax or UFCS, or their
// trait is a lang item.
struct CollectPrivateImplItemsVisitor<'a> {
exported_items: &'a privacy::ExportedItems,
access_levels: &'a privacy::AccessLevels,
worklist: &'a mut Vec<ast::NodeId>,
}

impl<'a, 'v> Visitor<'v> for CollectPrivateImplItemsVisitor<'a> {
fn visit_item(&mut self, item: &hir::Item) {
// We need only trait impls here, not inherent impls, and only non-exported ones
if let hir::ItemImpl(_, _, _, Some(_), _, ref impl_items) = item.node {
if !self.exported_items.contains(&item.id) {
if !self.access_levels.is_reachable(item.id) {
for impl_item in impl_items {
self.worklist.push(impl_item.id);
}
Expand All @@ -347,7 +347,7 @@ impl<'a, 'v> Visitor<'v> for CollectPrivateImplItemsVisitor<'a> {
}

pub fn find_reachable(tcx: &ty::ctxt,
exported_items: &privacy::ExportedItems)
access_levels: &privacy::AccessLevels)
-> NodeSet {

let mut reachable_context = ReachableContext::new(tcx);
Expand All @@ -357,7 +357,7 @@ pub fn find_reachable(tcx: &ty::ctxt,
// If other crates link to us, they're going to expect to be able to
// use the lang items, so we need to be sure to mark them as
// exported.
for id in exported_items {
for (id, _) in &access_levels.map {
reachable_context.worklist.push(*id);
}
for (_, item) in tcx.lang_items.items() {
Expand All @@ -369,7 +369,7 @@ pub fn find_reachable(tcx: &ty::ctxt,
}
{
let mut collect_private_impl_items = CollectPrivateImplItemsVisitor {
exported_items: exported_items,
access_levels: access_levels,
worklist: &mut reachable_context.worklist,
};
tcx.map.krate().visit_all_items(&mut collect_private_impl_items);
Expand Down
10 changes: 5 additions & 5 deletions src/librustc/middle/stability.rs
Expand Up @@ -19,7 +19,7 @@ use metadata::cstore::LOCAL_CRATE;
use middle::def;
use middle::def_id::{CRATE_DEF_INDEX, DefId};
use middle::ty;
use middle::privacy::PublicItems;
use middle::privacy::AccessLevels;
use metadata::csearch;
use syntax::parse::token::InternedString;
use syntax::codemap::{Span, DUMMY_SP};
Expand Down Expand Up @@ -73,7 +73,7 @@ struct Annotator<'a, 'tcx: 'a> {
tcx: &'a ty::ctxt<'tcx>,
index: &'a mut Index<'tcx>,
parent: Option<&'tcx Stability>,
export_map: &'a PublicItems,
access_levels: &'a AccessLevels,
in_trait_impl: bool,
in_enum: bool,
}
Expand Down Expand Up @@ -143,7 +143,7 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
} else {
debug!("annotate: not found, parent = {:?}", self.parent);
let mut is_error = kind == AnnotationKind::Required &&
self.export_map.contains(&id) &&
self.access_levels.is_reachable(id) &&
!self.tcx.sess.opts.test;
if let Some(stab) = self.parent {
if stab.level.is_unstable() {
Expand Down Expand Up @@ -266,12 +266,12 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> {

impl<'tcx> Index<'tcx> {
/// Construct the stability index for a crate being compiled.
pub fn build(&mut self, tcx: &ty::ctxt<'tcx>, krate: &'tcx Crate, export_map: &PublicItems) {
pub fn build(&mut self, tcx: &ty::ctxt<'tcx>, krate: &Crate, access_levels: &AccessLevels) {
let mut annotator = Annotator {
tcx: tcx,
index: self,
parent: None,
export_map: export_map,
access_levels: access_levels,
in_trait_impl: false,
in_enum: false,
};
Expand Down
4 changes: 1 addition & 3 deletions src/librustc/middle/ty/mod.rs
Expand Up @@ -104,14 +104,12 @@ pub const INITIAL_DISCRIMINANT_VALUE: Disr = 0;
/// produced by the driver and fed to trans and later passes.
pub struct CrateAnalysis<'a> {
pub export_map: ExportMap,
pub exported_items: middle::privacy::ExportedItems,
pub public_items: middle::privacy::PublicItems,
pub access_levels: middle::privacy::AccessLevels,
pub reachable: NodeSet,
pub name: &'a str,
pub glob_map: Option<GlobMap>,
}


#[derive(Copy, Clone)]
pub enum DtorKind {
NoDtor,
Expand Down
15 changes: 6 additions & 9 deletions src/librustc_driver/driver.rs
Expand Up @@ -746,7 +746,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
"const checking",
|| middle::check_const::check_crate(tcx));

let (exported_items, public_items) =
let access_levels =
time(time_passes, "privacy checking", || {
rustc_privacy::check_crate(tcx,
&export_map,
Expand All @@ -755,7 +755,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,

// Do not move this check past lint
time(time_passes, "stability index", || {
tcx.stability.borrow_mut().build(tcx, krate, &exported_items)
tcx.stability.borrow_mut().build(tcx, krate, &access_levels)
});

time(time_passes,
Expand Down Expand Up @@ -807,12 +807,10 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
let reachable_map =
time(time_passes,
"reachability checking",
|| reachable::find_reachable(tcx, &exported_items));
|| reachable::find_reachable(tcx, &access_levels));

time(time_passes, "death checking", || {
middle::dead::check_crate(tcx,
&exported_items,
&reachable_map)
middle::dead::check_crate(tcx, &access_levels);
});

let ref lib_features_used =
Expand All @@ -827,7 +825,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,

time(time_passes,
"lint checking",
|| lint::check_crate(tcx, &exported_items));
|| lint::check_crate(tcx, &access_levels));

// The above three passes generate errors w/o aborting
tcx.sess.abort_if_errors();
Expand All @@ -836,8 +834,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
mir_map,
ty::CrateAnalysis {
export_map: export_map,
exported_items: exported_items,
public_items: public_items,
access_levels: access_levels,
reachable: reachable_map,
name: name,
glob_map: glob_map,
Expand Down
12 changes: 6 additions & 6 deletions src/librustc_lint/builtin.rs
Expand Up @@ -301,8 +301,8 @@ impl MissingDoc {
// Only check publicly-visible items, using the result from the privacy pass.
// It's an option so the crate root can also use this function (it doesn't
// have a NodeId).
if let Some(ref id) = id {
if !cx.exported_items.contains(id) {
if let Some(id) = id {
if !cx.access_levels.is_exported(id) {
return;
}
}
Expand Down Expand Up @@ -470,7 +470,7 @@ impl LintPass for MissingCopyImplementations {

impl LateLintPass for MissingCopyImplementations {
fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
if !cx.exported_items.contains(&item.id) {
if !cx.access_levels.is_reachable(item.id) {
return;
}
let (def, ty) = match item.node {
Expand Down Expand Up @@ -534,7 +534,7 @@ impl LintPass for MissingDebugImplementations {

impl LateLintPass for MissingDebugImplementations {
fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
if !cx.exported_items.contains(&item.id) {
if !cx.access_levels.is_reachable(item.id) {
return;
}

Expand Down Expand Up @@ -987,15 +987,15 @@ impl LateLintPass for InvalidNoMangleItems {
match it.node {
hir::ItemFn(..) => {
if attr::contains_name(&it.attrs, "no_mangle") &&
!cx.exported_items.contains(&it.id) {
!cx.access_levels.is_reachable(it.id) {
let msg = format!("function {} is marked #[no_mangle], but not exported",
it.name);
cx.span_lint(PRIVATE_NO_MANGLE_FNS, it.span, &msg);
}
},
hir::ItemStatic(..) => {
if attr::contains_name(&it.attrs, "no_mangle") &&
!cx.exported_items.contains(&it.id) {
!cx.access_levels.is_reachable(it.id) {
let msg = format!("static {} is marked #[no_mangle], but not exported",
it.name);
cx.span_lint(PRIVATE_NO_MANGLE_STATICS, it.span, &msg);
Expand Down

0 comments on commit c1ad5af

Please sign in to comment.