Check adjustments and node substs

Cleanup checking of inherent static methods and fix checking of inherent associated constants
Add more tests
This commit is contained in:
Vadim Petrochenkov 2017-06-03 17:51:32 +03:00
parent 85fb9e0d91
commit 08a1d45818
5 changed files with 113 additions and 36 deletions

View file

@ -591,12 +591,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 {
@ -660,11 +671,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;
}
}
_ => {}
@ -673,6 +683,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) {
@ -769,25 +797,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;
}
}
@ -829,7 +843,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;

View file

@ -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;
@ -37,5 +40,5 @@ pub macro m() {
<u8 as PubTrait>::method;
PrivTupleStruct;
PubTupleStruct;
Pub::static_method;
Pub(0u8).priv_metod();
}

View file

@ -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)]

View file

@ -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)]
@ -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
@ -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

View file

@ -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
@ -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 {}