Skip to content

Commit

Permalink
Use recorded types in rustc_privacy
Browse files Browse the repository at this point in the history
  • Loading branch information
petrochenkov committed Sep 22, 2017
1 parent 505ff71 commit 419069d
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 121 deletions.
1 change: 1 addition & 0 deletions src/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/librustc_privacy/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ crate-type = ["dylib"]

[dependencies]
rustc = { path = "../librustc" }
rustc_typeck = { path = "../librustc_typeck" }
syntax = { path = "../libsyntax" }
syntax_pos = { path = "../libsyntax_pos" }
155 changes: 37 additions & 118 deletions src/librustc_privacy/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#[macro_use] extern crate rustc;
#[macro_use] extern crate syntax;
extern crate rustc_typeck;
extern crate syntax_pos;

use rustc::hir::{self, PatKind};
Expand Down Expand Up @@ -658,65 +659,6 @@ impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> {
}
false
}

fn check_item(&mut self, item_id: ast::NodeId) -> &mut Self {
self.current_item = self.tcx.hir.local_def_id(item_id);
self.span = self.tcx.hir.span(item_id);
self
}

// Convenience methods for checking item interfaces
fn ty(&mut self) -> &mut Self {
self.tcx.type_of(self.current_item).visit_with(self);
self
}

fn generics(&mut self) -> &mut Self {
for def in &self.tcx.generics_of(self.current_item).types {
if def.has_default {
self.tcx.type_of(def.def_id).visit_with(self);
}
}
self
}

fn predicates(&mut self) -> &mut Self {
let predicates = self.tcx.predicates_of(self.current_item);
for predicate in &predicates.predicates {
predicate.visit_with(self);
match predicate {
&ty::Predicate::Trait(poly_predicate) => {
self.check_trait_ref(poly_predicate.skip_binder().trait_ref);
},
&ty::Predicate::Projection(poly_predicate) => {
let tcx = self.tcx;
self.check_trait_ref(
poly_predicate.skip_binder().projection_ty.trait_ref(tcx)
);
},
_ => (),
};
}
self
}

fn impl_trait_ref(&mut self) -> &mut Self {
if let Some(impl_trait_ref) = self.tcx.impl_trait_ref(self.current_item) {
self.check_trait_ref(impl_trait_ref);
}
self.tcx.predicates_of(self.current_item).visit_with(self);
self
}

fn check_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>) -> bool {
if !self.item_is_accessible(trait_ref.def_id) {
let msg = format!("trait `{}` is private", trait_ref);
self.tcx.sess.span_err(self.span, &msg);
return true;
}

trait_ref.super_visit_with(self)
}
}

impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
Expand All @@ -733,6 +675,35 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
self.tables = orig_tables;
}

fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty) {
self.span = hir_ty.span;
if let Some(ty) = self.tables.node_id_to_type_opt(hir_ty.hir_id) {
// Types in bodies.
if ty.visit_with(self) {
return;
}
} else {
// Types in signatures.
// FIXME: This is very ineffective. Ideally each HIR type should be converted
// into a semantic type only once and the result should be cached somehow.
if rustc_typeck::hir_ty_to_ty(self.tcx, hir_ty).visit_with(self) {
return;
}
}

intravisit::walk_ty(self, hir_ty);
}

fn visit_trait_ref(&mut self, trait_ref: &'tcx hir::TraitRef) {
if !self.item_is_accessible(trait_ref.path.def.def_id()) {
let msg = format!("trait `{:?}` is private", trait_ref.path);
self.tcx.sess.span_err(self.span, &msg);
return;
}

intravisit::walk_trait_ref(self, trait_ref);
}

// Check types of expressions
fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
if self.check_expr_pat_type(expr.hir_id, expr.span) {
Expand Down Expand Up @@ -807,63 +778,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
item.id,
&mut self.tables,
self.empty_tables);

match item.node {
hir::ItemExternCrate(..) | hir::ItemMod(..) |
hir::ItemUse(..) | hir::ItemGlobalAsm(..) => {}
hir::ItemConst(..) | hir::ItemStatic(..) |
hir::ItemTy(..) | hir::ItemFn(..) => {
self.check_item(item.id).generics().predicates().ty();
}
hir::ItemTrait(.., ref trait_item_refs) => {
self.check_item(item.id).generics().predicates();
for trait_item_ref in trait_item_refs {
let check = self.check_item(trait_item_ref.id.node_id);
check.generics().predicates();
if trait_item_ref.kind != hir::AssociatedItemKind::Type ||
trait_item_ref.defaultness.has_value() {
check.ty();
}
}
}
hir::ItemEnum(ref def, _) => {
self.check_item(item.id).generics().predicates();
for variant in &def.variants {
for field in variant.node.data.fields() {
self.check_item(field.id).ty();
}
}
}
hir::ItemForeignMod(ref foreign_mod) => {
for foreign_item in &foreign_mod.items {
self.check_item(foreign_item.id).generics().predicates().ty();
}
}
hir::ItemStruct(ref struct_def, _) |
hir::ItemUnion(ref struct_def, _) => {
self.check_item(item.id).generics().predicates();
for field in struct_def.fields() {
self.check_item(field.id).ty();
}
}
hir::ItemDefaultImpl(..) => {
self.check_item(item.id).impl_trait_ref();
}
hir::ItemImpl(.., ref trait_ref, _, ref impl_item_refs) => {
{
let check = self.check_item(item.id);
check.ty().generics().predicates();
if trait_ref.is_some() {
check.impl_trait_ref();
}
}
for impl_item_ref in impl_item_refs {
let impl_item = self.tcx.hir.impl_item(impl_item_ref.id);
self.check_item(impl_item.id).generics().predicates().ty();
}
}
}

self.current_item = self.tcx.hir.local_def_id(item.id);
intravisit::walk_item(self, item);
self.tables = orig_tables;
Expand Down Expand Up @@ -924,8 +838,13 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
}
}
ty::TyProjection(ref proj) => {
let tcx = self.tcx;
if self.check_trait_ref(proj.trait_ref(tcx)) {
let trait_ref = proj.trait_ref(self.tcx);
if !self.item_is_accessible(trait_ref.def_id) {
let msg = format!("trait `{}` is private", trait_ref);
self.tcx.sess.span_err(self.span, &msg);
return true;
}
if trait_ref.super_visit_with(self) {
return true;
}
}
Expand Down
1 change: 1 addition & 0 deletions src/test/compile-fail/lint-stability-deprecated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ mod cross_crate {
struct S1<T: TraitWithAssociatedTypes>(T::TypeUnstable);
struct S2<T: TraitWithAssociatedTypes>(T::TypeDeprecated);
//~^ WARN use of deprecated item
//~| WARN use of deprecated item

let _ = DeprecatedStruct { //~ WARN use of deprecated item
i: 0 //~ WARN use of deprecated item
Expand Down
5 changes: 3 additions & 2 deletions src/test/compile-fail/private-inferred-type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,11 @@ mod adjust {

fn main() {
let _: m::Alias; //~ ERROR type `m::Priv` is private
let _: <m::Alias as m::TraitWithAssocTy>::AssocTy; // FIXME
//~^ ERROR type `m::Priv` is private
let _: <m::Alias as m::TraitWithAssocTy>::AssocTy; //~ ERROR type `m::Priv` is private
m::Alias {}; //~ ERROR type `m::Priv` is private
m::Pub { 0: m::Alias {} }; //~ ERROR type `m::Priv` is private
m::Pub { 0: loop {} }; // FIXME
m::Pub { 0: loop {} }; // OK, `m::Pub` is in value context, so it means Pub<_>, not Pub<Priv>
m::Pub::static_method; //~ ERROR type `m::Priv` is private
m::Pub::INHERENT_ASSOC_CONST; //~ ERROR type `m::Priv` is private
m::Pub(0u8).method_with_substs::<m::Alias>(); //~ ERROR type `m::Priv` is private
Expand Down
1 change: 0 additions & 1 deletion src/test/compile-fail/private-type-in-interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ fn f_ext(_: ext::Alias) {} //~ ERROR type `ext::Priv` is private
trait Tr1 {}
impl m::Alias {} //~ ERROR type `m::Priv` is private
impl Tr1 for ext::Alias {} //~ ERROR type `ext::Priv` is private
//~^ ERROR type `ext::Priv` is private
type A = <m::Alias as m::Trait>::X; //~ ERROR type `m::Priv` is private

trait Tr2<T> {}
Expand Down

0 comments on commit 419069d

Please sign in to comment.