Skip to content

Commit

Permalink
Check adjustments and node substs
Browse files Browse the repository at this point in the history
Cleanup checking of inherent static methods and fix checking of inherent associated constants
Add more tests
  • Loading branch information
petrochenkov committed Jun 3, 2017
1 parent c743e12 commit 5645122
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 36 deletions.
72 changes: 43 additions & 29 deletions src/librustc_privacy/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -589,12 +589,23 @@ impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> {
}

fn check_expr_pat_type(&mut self, id: ast::NodeId, span: Span) -> bool {
self.span = span;
if let Some(ty) = self.tables.node_id_to_type_opt(id) {
self.span = span;
ty.visit_with(self)
} else {
false
if ty.visit_with(self) {
return true;
}
}
if self.tables.node_substs(id).visit_with(self) {
return true;
}
if let Some(adjustments) = self.tables.adjustments.get(&id) {
for adjustment in adjustments {
if adjustment.target.visit_with(self) {
return true;
}
}
}
false
}

fn check_item(&mut self, item_id: ast::NodeId) -> &mut Self {
Expand Down Expand Up @@ -658,11 +669,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
}
hir::ExprMethodCall(name, ..) => {
// Method calls have to be checked specially.
if let Some(method) = self.tables.method_map.get(&ty::MethodCall::expr(expr.id)) {
self.span = name.span;
if method.ty.visit_with(self) || method.substs.visit_with(self) {
return;
}
let def_id = self.tables.type_dependent_defs[&expr.id].def_id();
self.span = name.span;
if self.tcx.type_of(def_id).visit_with(self) {
return;
}
}
_ => {}
Expand All @@ -671,6 +681,24 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
intravisit::walk_expr(self, expr);
}

fn visit_qpath(&mut self, qpath: &'tcx hir::QPath, id: ast::NodeId, span: Span) {
// Inherent associated constants don't have self type in substs,
// we have to check it additionally.
if let hir::QPath::TypeRelative(..) = *qpath {
if let Some(def) = self.tables.type_dependent_defs.get(&id).cloned() {
if let Some(assoc_item) = self.tcx.opt_associated_item(def.def_id()) {
if let ty::ImplContainer(impl_def_id) = assoc_item.container {
if self.tcx.type_of(impl_def_id).visit_with(self) {
return;
}
}
}
}
}

intravisit::walk_qpath(self, qpath, id, span);
}

// Check types of patterns
fn visit_pat(&mut self, pattern: &'tcx hir::Pat) {
if self.check_expr_pat_type(pattern.id, pattern.span) {
Expand Down Expand Up @@ -767,25 +795,11 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
self.tcx.sess.span_err(self.span, &msg);
return true;
}
if let ty::TyFnDef(..) = ty.sty {
// Inherent static methods don't have self type in substs,
// we have to check it additionally.
let mut impl_def_id = None;
if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
if let hir::map::NodeImplItem(..) = self.tcx.hir.get(node_id) {
impl_def_id = Some(self.tcx.hir.get_parent_did(node_id));
}
} else if let Some(Def::Method(..)) = self.tcx.describe_def(def_id) {
let candidate_impl_def_id = self.tcx.parent_def_id(def_id)
.expect("no parent for method def_id");
// `is_none` means it's an impl, not a trait
if self.tcx.describe_def(candidate_impl_def_id).is_none() {
impl_def_id = Some(candidate_impl_def_id)
}
}
if let Some(impl_def_id) = impl_def_id {
let self_ty = self.tcx.type_of(impl_def_id);
if self_ty.visit_with(self) {
// Inherent static methods don't have self type in substs,
// we have to check it additionally.
if let Some(assoc_item) = self.tcx.opt_associated_item(def_id) {
if let ty::ImplContainer(impl_def_id) = assoc_item.container {
if self.tcx.type_of(impl_def_id).visit_with(self) {
return true;
}
}
Expand Down Expand Up @@ -827,7 +841,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
self.tcx.sess.span_err(self.span, &msg);
return true;
}
// Skip `Self` to avoid infinite recursion
// `Self` here is the same `TyAnon`, so skip it to avoid infinite recursion
for subst in trait_ref.substs.iter().skip(1) {
if subst.visit_with(self) {
return true;
Expand Down
5 changes: 4 additions & 1 deletion src/test/compile-fail/auxiliary/private-inferred-type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ pub struct Pub<T = Alias>(pub T);
impl Pub<Priv> {
pub fn static_method() {}
}
impl Pub<u8> {
fn priv_metod(&self) {}
}

pub macro m() {
priv_fn;
Expand All @@ -37,5 +40,5 @@ pub macro m() {
<u8 as PubTrait>::method;
PrivTupleStruct;
PubTupleStruct;
Pub::static_method;
Pub(0u8).priv_metod();
}
2 changes: 1 addition & 1 deletion src/test/compile-fail/private-inferred-type-3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
// error-pattern:type `fn() {<u8 as ext::PrivTrait>::method}` is private
// error-pattern:type `fn(u8) -> ext::PrivTupleStruct {ext::PrivTupleStruct::{{constructor}}}` is pr
// error-pattern:type `fn(u8) -> ext::PubTupleStruct {ext::PubTupleStruct::{{constructor}}}` is priv
// error-pattern:type `ext::Priv` is private
// error-pattern:type `fn(&ext::Pub<u8>) {<ext::Pub<u8>>::priv_metod}` is private

#![feature(decl_macro)]

Expand Down
66 changes: 61 additions & 5 deletions src/test/compile-fail/private-inferred-type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(associated_consts)]
#![feature(conservative_impl_trait)]
#![feature(decl_macro)]

Expand All @@ -29,7 +30,19 @@ mod m {

impl Pub<Priv> {
pub fn static_method() {}
pub const INHERENT_ASSOC_CONST: u8 = 0;
}
impl<T> Pub<T> {
pub fn static_method_generic_self() {}
pub const INHERENT_ASSOC_CONST_GENERIC_SELF: u8 = 0;
}
impl Pub<u8> {
fn priv_metod(&self) {}
pub fn method_with_substs<T>(&self) {}
pub fn method_with_priv_params(&self, _: Priv) {}
}
impl TraitWithAssocConst for Priv {}
impl TraitWithAssocTy for Priv { type AssocTy = u8; }

pub macro m() {
priv_fn; //~ ERROR type `fn() {m::priv_fn}` is private
Expand All @@ -41,28 +54,71 @@ mod m {
//~^ ERROR type `fn(u8) -> m::PrivTupleStruct {m::PrivTupleStruct::{{constructor}}}` is priv
PubTupleStruct;
//~^ ERROR type `fn(u8) -> m::PubTupleStruct {m::PubTupleStruct::{{constructor}}}` is privat
Pub::static_method; //~ ERROR type `m::Priv` is private
Pub(0u8).priv_metod();
//~^ ERROR type `fn(&m::Pub<u8>) {<m::Pub<u8>>::priv_metod}` is private
}

trait Trait {}
pub trait TraitWithTyParam<T> {}
pub trait TraitWithAssocTy { type X; }
pub trait TraitWithTyParam2<T> { fn pub_method() {} }
pub trait TraitWithAssocTy { type AssocTy; }
pub trait TraitWithAssocConst { const TRAIT_ASSOC_CONST: u8 = 0; }
impl Trait for u8 {}
impl<T> TraitWithTyParam<T> for u8 {}
impl TraitWithAssocTy for u8 { type X = Priv; }
impl TraitWithTyParam2<Priv> for u8 {}
impl TraitWithAssocTy for u8 { type AssocTy = Priv; }

pub fn leak_anon1() -> impl Trait + 'static { 0 }
pub fn leak_anon2() -> impl TraitWithTyParam<Alias> { 0 }
pub fn leak_anon3() -> impl TraitWithAssocTy<X = Alias> { 0 }
pub fn leak_anon3() -> impl TraitWithAssocTy<AssocTy = Alias> { 0 }

pub fn leak_dyn1() -> Box<Trait + 'static> { Box::new(0) }
pub fn leak_dyn2() -> Box<TraitWithTyParam<Alias>> { Box::new(0) }
pub fn leak_dyn3() -> Box<TraitWithAssocTy<X = Alias>> { Box::new(0) }
pub fn leak_dyn3() -> Box<TraitWithAssocTy<AssocTy = Alias>> { Box::new(0) }
}

mod adjust {
// Construct a chain of derefs with a private type in the middle
use std::ops::Deref;

pub struct S1;
struct S2;
pub type S2Alias = S2;
pub struct S3;

impl Deref for S1 {
type Target = S2Alias;
fn deref(&self) -> &Self::Target { loop {} }
}
impl Deref for S2 {
type Target = S3;
fn deref(&self) -> &Self::Target { loop {} }
}

impl S3 {
pub fn method_s3(&self) {}
}
}

fn main() {
let _: m::Alias; //~ ERROR type `m::Priv` is private
let _: <m::Alias as m::TraitWithAssocTy>::AssocTy; // FIXME
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::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
m::Pub(0u8).method_with_priv_params(loop{}); //~ ERROR type `m::Priv` is private
<m::Alias as m::TraitWithAssocConst>::TRAIT_ASSOC_CONST; //~ ERROR type `m::Priv` is private
<m::Pub<m::Alias>>::INHERENT_ASSOC_CONST; //~ ERROR type `m::Priv` is private
<m::Pub<m::Alias>>::INHERENT_ASSOC_CONST_GENERIC_SELF; //~ ERROR type `m::Priv` is private
<m::Pub<m::Alias>>::static_method_generic_self; //~ ERROR type `m::Priv` is private
use m::TraitWithTyParam2;
u8::pub_method; //~ ERROR type `m::Priv` is private

adjust::S1.method_s3(); //~ ERROR type `adjust::S2` is private

m::m!();

m::leak_anon1(); //~ ERROR trait `m::Trait` is private
Expand Down
4 changes: 4 additions & 0 deletions src/test/compile-fail/private-type-in-interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ extern crate private_inferred_type as ext;
mod m {
struct Priv;
pub type Alias = Priv;

pub trait Trait { type X; }
impl Trait for Priv { type X = u8; }
}

fn f(_: m::Alias) {} //~ ERROR type `m::Priv` is private
Expand All @@ -28,6 +31,7 @@ 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> {}
impl<T> Tr2<T> for u8 {}
Expand Down

0 comments on commit 5645122

Please sign in to comment.