diff --git a/src/libproc_macro/quote.rs b/src/libproc_macro/quote.rs index bee2c1e0eb6b6..0db2b86b15f57 100644 --- a/src/libproc_macro/quote.rs +++ b/src/libproc_macro/quote.rs @@ -87,7 +87,7 @@ impl ProcMacro for Quoter { let mut info = cx.current_expansion.mark.expn_info().unwrap(); info.callee.allow_internal_unstable = true; cx.current_expansion.mark.set_expn_info(info); - ::__internal::set_sess(cx, || quote!(::TokenStream((quote stream)))) + ::__internal::set_sess(cx, || quote!(::TokenStream { 0: (quote stream) })) } } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 9eb96fea52778..051b89219c1f5 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -18,13 +18,13 @@ #![feature(rustc_diagnostic_macros)] -extern crate rustc; +#[macro_use] extern crate rustc; #[macro_use] extern crate syntax; extern crate syntax_pos; use rustc::hir::{self, PatKind}; use rustc::hir::def::Def; -use rustc::hir::def_id::{LOCAL_CRATE, CrateNum, DefId}; +use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, CrateNum, DefId}; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir::itemlikevisit::DeepVisitor; use rustc::lint; @@ -537,6 +537,344 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> { } } +//////////////////////////////////////////////////////////////////////////////////////////// +/// Type privacy visitor, checks types for privacy and reports violations. +/// Both explicitly written types and inferred types of expressions and patters are checked. +/// Checks are performed on "semantic" types regardless of names and their hygiene. +//////////////////////////////////////////////////////////////////////////////////////////// + +struct TypePrivacyVisitor<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + tables: &'a ty::TypeckTables<'tcx>, + current_item: DefId, + span: Span, +} + +impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> { + fn def_id_visibility(&self, did: DefId) -> ty::Visibility { + match self.tcx.hir.as_local_node_id(did) { + Some(node_id) => { + let vis = match self.tcx.hir.get(node_id) { + hir::map::NodeItem(item) => &item.vis, + hir::map::NodeForeignItem(foreign_item) => &foreign_item.vis, + hir::map::NodeImplItem(impl_item) => &impl_item.vis, + hir::map::NodeTraitItem(..) | + hir::map::NodeVariant(..) => { + return self.def_id_visibility(self.tcx.hir.get_parent_did(node_id)); + } + hir::map::NodeStructCtor(vdata) => { + let struct_node_id = self.tcx.hir.get_parent(node_id); + let struct_vis = match self.tcx.hir.get(struct_node_id) { + hir::map::NodeItem(item) => &item.vis, + node => bug!("unexpected node kind: {:?}", node), + }; + let mut ctor_vis + = ty::Visibility::from_hir(struct_vis, struct_node_id, self.tcx); + for field in vdata.fields() { + let field_vis = ty::Visibility::from_hir(&field.vis, node_id, self.tcx); + if ctor_vis.is_at_least(field_vis, self.tcx) { + ctor_vis = field_vis; + } + } + return ctor_vis; + } + node => bug!("unexpected node kind: {:?}", node) + }; + ty::Visibility::from_hir(vis, node_id, self.tcx) + } + None => self.tcx.sess.cstore.visibility(did), + } + } + + fn item_is_accessible(&self, did: DefId) -> bool { + self.def_id_visibility(did).is_accessible_from(self.current_item, self.tcx) + } + + // Take node ID of an expression or pattern and check its type for privacy. + 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) { + 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 { + 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 { + self.tcx.predicates_of(self.current_item).visit_with(self); + self + } + + fn impl_trait_ref(&mut self) -> &mut Self { + self.tcx.impl_trait_ref(self.current_item).visit_with(self); + self + } +} + +impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { + /// We want to visit items in the context of their containing + /// module and so forth, so supply a crate for doing a deep walk. + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { + NestedVisitorMap::All(&self.tcx.hir) + } + + fn visit_nested_body(&mut self, body: hir::BodyId) { + let orig_tables = replace(&mut self.tables, self.tcx.body_tables(body)); + let body = self.tcx.hir.body(body); + self.visit_body(body); + self.tables = orig_tables; + } + + // Check types of expressions + fn visit_expr(&mut self, expr: &'tcx hir::Expr) { + if self.check_expr_pat_type(expr.id, expr.span) { + // Do not check nested expressions if the error already happened. + return; + } + match expr.node { + hir::ExprAssign(.., ref rhs) | hir::ExprMatch(ref rhs, ..) => { + // Do not report duplicate errors for `x = y` and `match x { ... }`. + if self.check_expr_pat_type(rhs.id, rhs.span) { + return; + } + } + hir::ExprMethodCall(name, ..) => { + // Method calls have to be checked specially. + 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; + } + } + _ => {} + } + + 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) { + // Do not check nested patterns if the error already happened. + return; + } + + intravisit::walk_pat(self, pattern); + } + + fn visit_local(&mut self, local: &'tcx hir::Local) { + if let Some(ref init) = local.init { + if self.check_expr_pat_type(init.id, init.span) { + // Do not report duplicate errors for `let x = y`. + return; + } + } + + intravisit::walk_local(self, local); + } + + // Check types in item interfaces + fn visit_item(&mut self, item: &'tcx hir::Item) { + let orig_current_item = self.current_item; + + 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 mut 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 mut 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.current_item = orig_current_item; + } +} + +impl<'a, 'tcx> TypeVisitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { + match ty.sty { + ty::TyAdt(&ty::AdtDef { did: def_id, .. }, ..) | ty::TyFnDef(def_id, ..) => { + if !self.item_is_accessible(def_id) { + let msg = format!("type `{}` is private", ty); + self.tcx.sess.span_err(self.span, &msg); + return true; + } + if let ty::TyFnDef(..) = ty.sty { + if self.tcx.fn_sig(def_id).visit_with(self) { + return true; + } + } + // 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; + } + } + } + } + ty::TyDynamic(ref predicates, ..) => { + let is_private = predicates.skip_binder().iter().any(|predicate| { + let def_id = match *predicate { + ty::ExistentialPredicate::Trait(trait_ref) => trait_ref.def_id, + ty::ExistentialPredicate::Projection(proj) => proj.trait_ref.def_id, + ty::ExistentialPredicate::AutoTrait(def_id) => def_id, + }; + !self.item_is_accessible(def_id) + }); + if is_private { + let msg = format!("type `{}` is private", ty); + self.tcx.sess.span_err(self.span, &msg); + return true; + } + } + ty::TyAnon(def_id, ..) => { + for predicate in &self.tcx.predicates_of(def_id).predicates { + let trait_ref = match *predicate { + ty::Predicate::Trait(ref poly_trait_predicate) => { + Some(poly_trait_predicate.skip_binder().trait_ref) + } + ty::Predicate::Projection(ref poly_projection_predicate) => { + if poly_projection_predicate.skip_binder().ty.visit_with(self) { + return true; + } + Some(poly_projection_predicate.skip_binder().projection_ty.trait_ref) + } + ty::Predicate::TypeOutlives(..) => None, + _ => bug!("unexpected predicate: {:?}", predicate), + }; + if let Some(trait_ref) = trait_ref { + 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; + } + // `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; + } + } + } + } + } + _ => {} + } + + ty.super_visit_with(self) + } + + fn visit_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) + } +} + /////////////////////////////////////////////////////////////////////////////// /// Obsolete visitors for checking for private items in public interfaces. /// These visitors are supposed to be kept in frozen state and produce an @@ -1225,6 +1563,16 @@ fn privacy_access_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; intravisit::walk_crate(&mut visitor, krate); + // Check privacy of explicitly written types and traits as well as + // inferred types of expressions and patterns. + let mut visitor = TypePrivacyVisitor { + tcx: tcx, + tables: &ty::TypeckTables::empty(), + current_item: DefId::local(CRATE_DEF_INDEX), + span: krate.span, + }; + intravisit::walk_crate(&mut visitor, krate); + // Build up a set of all exported items in the AST. This is a set of all // items which are reachable from external crates based on visibility. let mut visitor = EmbargoVisitor { diff --git a/src/test/compile-fail/auxiliary/private-inferred-type.rs b/src/test/compile-fail/auxiliary/private-inferred-type.rs new file mode 100644 index 0000000000000..7627f5dc0cd09 --- /dev/null +++ b/src/test/compile-fail/auxiliary/private-inferred-type.rs @@ -0,0 +1,44 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(decl_macro)] + +fn priv_fn() {} +enum PrivEnum { Variant } +pub enum PubEnum { Variant } +trait PrivTrait { fn method() {} } +impl PrivTrait for u8 {} +pub trait PubTrait { fn method() {} } +impl PubTrait for u8 {} +struct PrivTupleStruct(u8); +pub struct PubTupleStruct(u8); +impl PubTupleStruct { fn method() {} } + +struct Priv; +pub type Alias = Priv; +pub struct Pub(pub T); + +impl Pub { + pub fn static_method() {} +} +impl Pub { + fn priv_method(&self) {} +} + +pub macro m() { + priv_fn; + PrivEnum::Variant; + PubEnum::Variant; + ::method; + ::method; + PrivTupleStruct; + PubTupleStruct; + Pub(0u8).priv_method(); +} diff --git a/src/test/run-pass/hygiene/auxiliary/intercrate.rs b/src/test/compile-fail/hygiene/auxiliary/intercrate.rs similarity index 100% rename from src/test/run-pass/hygiene/auxiliary/intercrate.rs rename to src/test/compile-fail/hygiene/auxiliary/intercrate.rs diff --git a/src/test/run-pass/hygiene/fields.rs b/src/test/compile-fail/hygiene/fields.rs similarity index 78% rename from src/test/run-pass/hygiene/fields.rs rename to src/test/compile-fail/hygiene/fields.rs index d7f99ba2118e8..64217770b13c9 100644 --- a/src/test/run-pass/hygiene/fields.rs +++ b/src/test/compile-fail/hygiene/fields.rs @@ -22,11 +22,11 @@ mod foo { x: i32, } - let s = S { x: 0 }; - let _ = s.x; + let s = S { x: 0 }; //~ ERROR type `foo::S` is private + let _ = s.x; //~ ERROR type `foo::S` is private - let t = T(0); - let _ = t.0; + let t = T(0); //~ ERROR type `foo::T` is private + let _ = t.0; //~ ERROR type `foo::T` is private let s = $S { $x: 0, x: 1 }; assert_eq!((s.$x, s.x), (0, 1)); diff --git a/src/test/run-pass/hygiene/impl_items.rs b/src/test/compile-fail/hygiene/impl_items.rs similarity index 91% rename from src/test/run-pass/hygiene/impl_items.rs rename to src/test/compile-fail/hygiene/impl_items.rs index a5780a573aba1..445aa62f2361e 100644 --- a/src/test/run-pass/hygiene/impl_items.rs +++ b/src/test/compile-fail/hygiene/impl_items.rs @@ -19,7 +19,7 @@ mod foo { } pub macro m() { - let _: () = S.f(); + let _: () = S.f(); //~ ERROR type `fn(&foo::S) {foo::S::f}` is private } } diff --git a/src/test/run-pass/hygiene/intercrate.rs b/src/test/compile-fail/hygiene/intercrate.rs similarity index 89% rename from src/test/run-pass/hygiene/intercrate.rs rename to src/test/compile-fail/hygiene/intercrate.rs index 3a75085f22e4e..50fc985ba34fa 100644 --- a/src/test/run-pass/hygiene/intercrate.rs +++ b/src/test/compile-fail/hygiene/intercrate.rs @@ -12,6 +12,8 @@ // aux-build:intercrate.rs +// error-pattern:type `fn() -> u32 {intercrate::foo::bar::f}` is private + #![feature(decl_macro)] extern crate intercrate; diff --git a/src/test/compile-fail/private-inferred-type-1.rs b/src/test/compile-fail/private-inferred-type-1.rs new file mode 100644 index 0000000000000..ba8b3d1810a05 --- /dev/null +++ b/src/test/compile-fail/private-inferred-type-1.rs @@ -0,0 +1,28 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Arr0 { + fn arr0_secret(&self); +} +trait TyParam { + fn ty_param_secret(&self); +} + +mod m { + struct Priv; + + impl ::Arr0 for [Priv; 0] { fn arr0_secret(&self) {} } + impl ::TyParam for Option { fn ty_param_secret(&self) {} } +} + +fn main() { + [].arr0_secret(); //~ ERROR type `m::Priv` is private + None.ty_param_secret(); //~ ERROR type `m::Priv` is private +} diff --git a/src/test/compile-fail/private-inferred-type-2.rs b/src/test/compile-fail/private-inferred-type-2.rs new file mode 100644 index 0000000000000..e981f12575015 --- /dev/null +++ b/src/test/compile-fail/private-inferred-type-2.rs @@ -0,0 +1,29 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:private-inferred-type.rs + +extern crate private_inferred_type as ext; + +mod m { + struct Priv; + pub struct Pub(pub T); + + impl Pub { + pub fn get_priv() -> Priv { Priv } + pub fn static_method() {} + } +} + +fn main() { + m::Pub::get_priv; //~ ERROR type `m::Priv` is private + m::Pub::static_method; //~ ERROR type `m::Priv` is private + ext::Pub::static_method; //~ ERROR type `ext::Priv` is private +} diff --git a/src/test/compile-fail/private-inferred-type-3.rs b/src/test/compile-fail/private-inferred-type-3.rs new file mode 100644 index 0000000000000..fdd9166ef2999 --- /dev/null +++ b/src/test/compile-fail/private-inferred-type-3.rs @@ -0,0 +1,26 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:private-inferred-type.rs + +// error-pattern:type `fn() {ext::priv_fn}` is private +// error-pattern:type `ext::PrivEnum` is private +// 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 `fn(&ext::Pub) {>::priv_method}` is private + +#![feature(decl_macro)] + +extern crate private_inferred_type as ext; + +fn main() { + ext::m!(); +} diff --git a/src/test/compile-fail/private-inferred-type.rs b/src/test/compile-fail/private-inferred-type.rs new file mode 100644 index 0000000000000..140891027d5f0 --- /dev/null +++ b/src/test/compile-fail/private-inferred-type.rs @@ -0,0 +1,139 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// 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)] + +mod m { + fn priv_fn() {} + enum PrivEnum { Variant } + pub enum PubEnum { Variant } + trait PrivTrait { fn method() {} } + impl PrivTrait for u8 {} + pub trait PubTrait { fn method() {} } + impl PubTrait for u8 {} + struct PrivTupleStruct(u8); + pub struct PubTupleStruct(u8); + impl PubTupleStruct { fn method() {} } + + struct Priv; + pub type Alias = Priv; + pub struct Pub(pub T); + + 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_method(&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 + PrivEnum::Variant; //~ ERROR type `m::PrivEnum` is private + PubEnum::Variant; // OK + ::method; //~ ERROR type `fn() {::method}` is private + ::method; // OK + PrivTupleStruct; + //~^ ERROR type `fn(u8) -> m::PrivTupleStruct {m::PrivTupleStruct::{{constructor}}}` is priv + PubTupleStruct; + //~^ ERROR type `fn(u8) -> m::PubTupleStruct {m::PubTupleStruct::{{constructor}}}` is privat + Pub(0u8).priv_method(); + //~^ ERROR type `fn(&m::Pub) {>::priv_method}` is private + } + + trait Trait {} + pub trait TraitWithTyParam {} + 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 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_dyn1() -> Box { Box::new(0) } + pub fn leak_dyn2() -> 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 + m::leak_anon2(); //~ ERROR type `m::Priv` is private + m::leak_anon3(); //~ ERROR type `m::Priv` is private + + m::leak_dyn1(); //~ ERROR type `m::Trait + 'static` is private + m::leak_dyn2(); //~ ERROR type `m::Priv` is private + m::leak_dyn3(); //~ ERROR type `m::Priv` is private + + // Check that messages are not duplicated for various kinds of assignments + let a = m::Alias {}; //~ ERROR type `m::Priv` is private + let mut b = a; //~ ERROR type `m::Priv` is private + b = a; //~ ERROR type `m::Priv` is private + match a { //~ ERROR type `m::Priv` is private + _ => {} + } +} diff --git a/src/test/compile-fail/private-type-in-interface.rs b/src/test/compile-fail/private-type-in-interface.rs new file mode 100644 index 0000000000000..925d692f8ae6b --- /dev/null +++ b/src/test/compile-fail/private-type-in-interface.rs @@ -0,0 +1,41 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:private-inferred-type.rs + +#![feature(conservative_impl_trait)] + +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 + //~^ ERROR type `m::Priv` is private +fn f_ext(_: ext::Alias) {} //~ ERROR type `ext::Priv` is private + //~^ 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 = ::X; //~ ERROR type `m::Priv` is private + +trait Tr2 {} +impl Tr2 for u8 {} +fn g() -> impl Tr2 { 0 } //~ ERROR type `m::Priv` is private +fn g_ext() -> impl Tr2 { 0 } //~ ERROR type `ext::Priv` is private + +fn main() {}