From 56451228a799122a60ca41859993e3de4309ced9 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 3 Jun 2017 17:51:32 +0300 Subject: [PATCH] Check adjustments and node substs Cleanup checking of inherent static methods and fix checking of inherent associated constants Add more tests --- src/librustc_privacy/lib.rs | 72 +++++++++++-------- .../auxiliary/private-inferred-type.rs | 5 +- .../compile-fail/private-inferred-type-3.rs | 2 +- .../compile-fail/private-inferred-type.rs | 66 +++++++++++++++-- .../compile-fail/private-type-in-interface.rs | 4 ++ 5 files changed, 113 insertions(+), 36 deletions(-) diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index ecc92acff6491..2fc5553d438c6 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -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 { @@ -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; } } _ => {} @@ -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) { @@ -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; } } @@ -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; diff --git a/src/test/compile-fail/auxiliary/private-inferred-type.rs b/src/test/compile-fail/auxiliary/private-inferred-type.rs index 1230ae8f84ae0..28bf9e08157ec 100644 --- a/src/test/compile-fail/auxiliary/private-inferred-type.rs +++ b/src/test/compile-fail/auxiliary/private-inferred-type.rs @@ -28,6 +28,9 @@ pub struct Pub(pub T); impl Pub { pub fn static_method() {} } +impl Pub { + fn priv_metod(&self) {} +} pub macro m() { priv_fn; @@ -37,5 +40,5 @@ pub macro m() { ::method; PrivTupleStruct; PubTupleStruct; - Pub::static_method; + Pub(0u8).priv_metod(); } diff --git a/src/test/compile-fail/private-inferred-type-3.rs b/src/test/compile-fail/private-inferred-type-3.rs index fb9357f9373b7..438dd5e1933b8 100644 --- a/src/test/compile-fail/private-inferred-type-3.rs +++ b/src/test/compile-fail/private-inferred-type-3.rs @@ -15,7 +15,7 @@ // error-pattern:type `fn() {::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) {>::priv_metod}` is private #![feature(decl_macro)] diff --git a/src/test/compile-fail/private-inferred-type.rs b/src/test/compile-fail/private-inferred-type.rs index 6f39872ecf6cf..c00bfe5e57479 100644 --- a/src/test/compile-fail/private-inferred-type.rs +++ b/src/test/compile-fail/private-inferred-type.rs @@ -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 { pub fn static_method() {} + pub const INHERENT_ASSOC_CONST: u8 = 0; } + impl Pub { + pub fn static_method_generic_self() {} + pub const INHERENT_ASSOC_CONST_GENERIC_SELF: u8 = 0; + } + impl Pub { + fn priv_metod(&self) {} + pub fn method_with_substs(&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) {>::priv_metod}` is private } trait Trait {} pub trait TraitWithTyParam {} - pub trait TraitWithAssocTy { type X; } + pub trait TraitWithTyParam2 { fn pub_method() {} } + pub trait TraitWithAssocTy { type AssocTy; } + pub trait TraitWithAssocConst { const TRAIT_ASSOC_CONST: u8 = 0; } impl Trait for u8 {} impl TraitWithTyParam for u8 {} - impl TraitWithAssocTy for u8 { type X = Priv; } + impl TraitWithTyParam2 for u8 {} + impl TraitWithAssocTy for u8 { type AssocTy = Priv; } pub fn leak_anon1() -> impl Trait + 'static { 0 } pub fn leak_anon2() -> impl TraitWithTyParam { 0 } - pub fn leak_anon3() -> impl TraitWithAssocTy { 0 } + pub fn leak_anon3() -> impl TraitWithAssocTy { 0 } pub fn leak_dyn1() -> Box { Box::new(0) } pub fn leak_dyn2() -> Box> { Box::new(0) } - pub fn leak_dyn3() -> Box> { Box::new(0) } + pub fn leak_dyn3() -> Box> { 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 _: ::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::(); //~ ERROR type `m::Priv` is private + m::Pub(0u8).method_with_priv_params(loop{}); //~ ERROR type `m::Priv` is private + ::TRAIT_ASSOC_CONST; //~ ERROR type `m::Priv` is private + >::INHERENT_ASSOC_CONST; //~ ERROR type `m::Priv` is private + >::INHERENT_ASSOC_CONST_GENERIC_SELF; //~ ERROR type `m::Priv` is private + >::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 diff --git a/src/test/compile-fail/private-type-in-interface.rs b/src/test/compile-fail/private-type-in-interface.rs index e4b52895c14e2..925d692f8ae6b 100644 --- a/src/test/compile-fail/private-type-in-interface.rs +++ b/src/test/compile-fail/private-type-in-interface.rs @@ -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 = ::X; //~ ERROR type `m::Priv` is private trait Tr2 {} impl Tr2 for u8 {}