From 8dcd26a6df4bb932cd94404a6c941d84a3d1d851 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 23 Sep 2017 20:48:08 +0300 Subject: [PATCH 1/5] Add tests for associated item privacy --- .../associated-item-privacy-inherent.rs | 122 ++++++++++++++ .../privacy/associated-item-privacy-trait.rs | 152 ++++++++++++++++++ .../associated-item-privacy-type-binding.rs | 75 +++++++++ 3 files changed, 349 insertions(+) create mode 100644 src/test/compile-fail/privacy/associated-item-privacy-inherent.rs create mode 100644 src/test/compile-fail/privacy/associated-item-privacy-trait.rs create mode 100644 src/test/compile-fail/privacy/associated-item-privacy-type-binding.rs diff --git a/src/test/compile-fail/privacy/associated-item-privacy-inherent.rs b/src/test/compile-fail/privacy/associated-item-privacy-inherent.rs new file mode 100644 index 000000000000..d742a3a19422 --- /dev/null +++ b/src/test/compile-fail/privacy/associated-item-privacy-inherent.rs @@ -0,0 +1,122 @@ +// 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, associated_type_defaults)] +#![allow(unused, private_in_public)] + +mod priv_nominal { + pub struct Pub; + impl Pub { + fn method(&self) {} + const CONST: u8 = 0; + // type AssocTy = u8; + } + + pub macro mac() { + let value = Pub::method; + //~^ ERROR type `for<'r> fn(&'r priv_nominal::Pub) {priv_nominal::Pub::method}` is private + value; + //~^ ERROR type `for<'r> fn(&'r priv_nominal::Pub) {priv_nominal::Pub::method}` is private + Pub.method(); + //~^ ERROR type `for<'r> fn(&'r priv_nominal::Pub) {priv_nominal::Pub::method}` is private + Pub::CONST; + //FIXME ERROR associated constant `CONST` is private + // let _: Pub::AssocTy; + // pub type InSignatureTy = Pub::AssocTy; + } +} +fn priv_nominal() { + priv_nominal::mac!(); +} + +mod priv_signature { + struct Priv; + pub struct Pub; + impl Pub { + pub fn method(&self, arg: Priv) {} + } + + pub macro mac() { + let value = Pub::method; + //~^ ERROR type `priv_signature::Priv` is private + value; + //~^ ERROR type `priv_signature::Priv` is private + Pub.method(loop {}); + //~^ ERROR type `priv_signature::Priv` is private + } +} +fn priv_signature() { + priv_signature::mac!(); +} + +mod priv_substs { + struct Priv; + pub struct Pub; + impl Pub { + pub fn method(&self) {} + } + + pub macro mac() { + let value = Pub::method::; + //~^ ERROR type `priv_substs::Priv` is private + value; + //~^ ERROR type `priv_substs::Priv` is private + Pub.method::(); + //~^ ERROR type `priv_substs::Priv` is private + } +} +fn priv_substs() { + priv_substs::mac!(); +} + +mod priv_parent_substs { + struct Priv; + pub struct Pub(T); + impl Pub { + pub fn method(&self) {} + pub fn static_method() {} + pub const CONST: u8 = 0; + // pub type AssocTy = u8; + } + + pub macro mac() { + let value = ::method; + //~^ ERROR type `priv_parent_substs::Priv` is private + value; + //~^ ERROR type `priv_parent_substs::Priv` is private + let value = Pub::method; + //~^ ERROR type `priv_parent_substs::Priv` is private + value; + //~^ ERROR type `priv_parent_substs::Priv` is private + let value = ::static_method; + //~^ ERROR type `priv_parent_substs::Priv` is private + value; + //~^ ERROR type `priv_parent_substs::Priv` is private + let value = Pub::static_method; + //~^ ERROR type `priv_parent_substs::Priv` is private + value; + //~^ ERROR type `priv_parent_substs::Priv` is private + Pub(Priv).method(); + //~^ ERROR type `priv_parent_substs::Priv` is private + + ::CONST; + //~^ ERROR type `priv_parent_substs::Priv` is private + Pub::CONST; + //~^ ERROR type `priv_parent_substs::Priv` is private + + // let _: Pub::AssocTy; + // pub type InSignatureTy = Pub::AssocTy; + } +} +fn priv_parent_substs() { + priv_parent_substs::mac!(); +} + +fn main() {} diff --git a/src/test/compile-fail/privacy/associated-item-privacy-trait.rs b/src/test/compile-fail/privacy/associated-item-privacy-trait.rs new file mode 100644 index 000000000000..d68c50228490 --- /dev/null +++ b/src/test/compile-fail/privacy/associated-item-privacy-trait.rs @@ -0,0 +1,152 @@ +// 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. + +// ignore-tidy-linelength + +#![feature(decl_macro, associated_type_defaults)] +#![allow(unused, private_in_public)] + +mod priv_trait { + trait PrivTr { + fn method(&self) {} + const CONST: u8 = 0; + type AssocTy = u8; + } + pub struct Pub; + impl PrivTr for Pub {} + pub trait PubTr: PrivTr {} + + pub macro mac() { + let value = ::method; + //~^ ERROR type `for<'r> fn(&'r priv_trait::Pub) {::method}` is private + value; + //~^ ERROR type `for<'r> fn(&'r priv_trait::Pub) {::method}` is private + Pub.method(); + //~^ ERROR type `for<'r> fn(&'r Self) {::method}` is private + ::CONST; + //FIXME ERROR associated constant `path(PrivTr::CONST)` is private + let _: ::AssocTy; + //~^ ERROR trait `priv_trait::PrivTr` is private + //~| ERROR trait `priv_trait::PrivTr` is private + pub type InSignatureTy = ::AssocTy; + //~^ ERROR trait `priv_trait::PrivTr` is private + //~| ERROR trait `path(PrivTr)` is private + pub trait InSignatureTr: PrivTr {} + //FIXME ERROR trait `priv_trait::PrivTr` is private + impl PrivTr for u8 {} + //FIXME ERROR trait `priv_trait::PrivTr` is private + } +} +fn priv_trait() { + priv_trait::mac!(); +} + +mod priv_signature { + pub trait PubTr { + fn method(&self, arg: Priv) {} + } + struct Priv; + pub struct Pub; + impl PubTr for Pub {} + + pub macro mac() { + let value = ::method; + //~^ ERROR type `priv_signature::Priv` is private + value; + //~^ ERROR type `priv_signature::Priv` is private + Pub.method(loop {}); + //~^ ERROR type `priv_signature::Priv` is private + } +} +fn priv_signature() { + priv_signature::mac!(); +} + +mod priv_substs { + pub trait PubTr { + fn method(&self) {} + } + struct Priv; + pub struct Pub; + impl PubTr for Pub {} + + pub macro mac() { + let value = ::method::; + //~^ ERROR type `priv_substs::Priv` is private + value; + //~^ ERROR type `priv_substs::Priv` is private + Pub.method::(); + //~^ ERROR type `priv_substs::Priv` is private + } +} +fn priv_substs() { + priv_substs::mac!(); +} + +mod priv_parent_substs { + pub trait PubTr { + fn method(&self) {} + const CONST: u8 = 0; + type AssocTy = u8; + } + struct Priv; + pub struct Pub; + impl PubTr for Pub {} + impl PubTr for Priv {} + + pub macro mac() { + let value = ::method; + //~^ ERROR type `priv_parent_substs::Priv` is private + value; + //~^ ERROR type `priv_parent_substs::Priv` is private + let value = >::method; + //~^ ERROR type `priv_parent_substs::Priv` is private + value; + //~^ ERROR type `priv_parent_substs::Priv` is private + Pub.method(); + //~^ ERROR type `priv_parent_substs::Priv` is private + + let value = >::method; + //~^ ERROR type `priv_parent_substs::Priv` is private + value; + //~^ ERROR type `priv_parent_substs::Priv` is private + Priv.method(); + //~^ ERROR type `priv_parent_substs::Priv` is private + + ::CONST; + //~^ ERROR type `priv_parent_substs::Priv` is private + >::CONST; + //~^ ERROR type `priv_parent_substs::Priv` is private + >::CONST; + //~^ ERROR type `priv_parent_substs::Priv` is private + + let _: ::AssocTy; + //~^ ERROR type `priv_parent_substs::Priv` is private + //~| ERROR type `priv_parent_substs::Priv` is private + let _: >::AssocTy; + //~^ ERROR type `priv_parent_substs::Priv` is private + //~| ERROR type `priv_parent_substs::Priv` is private + let _: >::AssocTy; + //~^ ERROR type `priv_parent_substs::Priv` is private + //~| ERROR type `priv_parent_substs::Priv` is private + + pub type InSignatureTy1 = ::AssocTy; + //~^ ERROR type `priv_parent_substs::Priv` is private + pub type InSignatureTy2 = >::AssocTy; + //~^ ERROR type `priv_parent_substs::Priv` is private + impl PubTr for u8 {} + //FIXME ERROR type `priv_parent_substs::Priv` is private + } +} +fn priv_parent_substs() { + priv_parent_substs::mac!(); +} + +fn main() {} diff --git a/src/test/compile-fail/privacy/associated-item-privacy-type-binding.rs b/src/test/compile-fail/privacy/associated-item-privacy-type-binding.rs new file mode 100644 index 000000000000..f191ff14dce6 --- /dev/null +++ b/src/test/compile-fail/privacy/associated-item-privacy-type-binding.rs @@ -0,0 +1,75 @@ +// 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, associated_type_defaults)] +#![allow(unused, private_in_public)] + +mod priv_trait { + trait PrivTr { + type AssocTy = u8; + } + pub trait PubTr: PrivTr {} + + pub macro mac1() { + let _: Box>; + //~^ ERROR type `priv_trait::PubTr + '` is private + //~| ERROR type `priv_trait::PubTr + '` is private + type InSignatureTy2 = Box>; + //~^ ERROR type `priv_trait::PubTr + 'static` is private + trait InSignatureTr2: PubTr {} + //FIXME ERROR trait `priv_trait::PrivTr` is private + } + pub macro mac2() { + let _: Box>; + //~^ ERROR type `priv_trait::PrivTr + '` is private + //~| ERROR type `priv_trait::PrivTr + '` is private + type InSignatureTy1 = Box>; + //~^ ERROR type `priv_trait::PrivTr + 'static` is private + //~| ERROR trait `path(PrivTr)` is private + trait InSignatureTr1: PrivTr {} + //FIXME ERROR trait `priv_trait::PrivTr` is private + } +} +fn priv_trait1() { + priv_trait::mac1!(); +} +fn priv_trait2() { + priv_trait::mac2!(); +} + +mod priv_parent_substs { + pub trait PubTrWithParam { + type AssocTy = u8; + } + struct Priv; + pub trait PubTr: PubTrWithParam {} + + pub macro mac() { + let _: Box>; + //~^ ERROR type `priv_parent_substs::Priv` is private + //~| ERROR type `priv_parent_substs::Priv` is private + let _: Box>; + //~^ ERROR type `priv_parent_substs::Priv` is private + //~| ERROR type `priv_parent_substs::Priv` is private + pub type InSignatureTy1 = Box>; + //~^ ERROR type `priv_parent_substs::Priv` is private + pub type InSignatureTy2 = Box>; + //~^ ERROR type `priv_parent_substs::Priv` is private + trait InSignatureTr1: PubTrWithParam {} + //FIXME ERROR type `priv_parent_substs::Priv` is private + trait InSignatureTr2: PubTr {} + //FIXME ERROR type `priv_parent_substs::Priv` is private + } +} +fn priv_parent_substs() { + priv_parent_substs::mac!(); +} + +fn main() {} From 53779ed5ec8077fd11d5ea9c3e0e1c404ee92c36 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 18 Nov 2017 18:38:56 +0300 Subject: [PATCH 2/5] Check associated type bindings for privacy and stability --- src/librustc_typeck/astconv.rs | 50 ++++++++++--------- .../compile-fail/lint-stability-deprecated.rs | 5 ++ src/test/compile-fail/lint-stability.rs | 4 ++ src/test/compile-fail/trait-item-privacy.rs | 10 ++++ 4 files changed, 45 insertions(+), 24 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 6b37a30cb82d..ba0e79168922 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -370,7 +370,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { poly_projections.extend(assoc_bindings.iter().filter_map(|binding| { // specify type to assert that error was already reported in Err case: let predicate: Result<_, ErrorReported> = - self.ast_type_binding_to_poly_projection_predicate(poly_trait_ref, binding); + self.ast_type_binding_to_poly_projection_predicate(trait_ref.ref_id, poly_trait_ref, + binding); predicate.ok() // ok to ignore Err() because ErrorReported (see above) })); @@ -442,6 +443,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { fn ast_type_binding_to_poly_projection_predicate( &self, + ref_id: ast::NodeId, trait_ref: ty::PolyTraitRef<'tcx>, binding: &ConvertedBinding<'tcx>) -> Result, ErrorReported> @@ -494,30 +496,30 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { .emit(); } - // Simple case: X is defined in the current trait. - if self.trait_defines_associated_type_named(trait_ref.def_id(), binding.item_name) { - return Ok(trait_ref.map_bound(|trait_ref| { - ty::ProjectionPredicate { - projection_ty: ty::ProjectionTy::from_ref_and_name( - tcx, - trait_ref, - binding.item_name, - ), - ty: binding.ty, - } - })); + let candidate = if self.trait_defines_associated_type_named(trait_ref.def_id(), + binding.item_name) { + // Simple case: X is defined in the current trait. + Ok(trait_ref) + } else { + // Otherwise, we have to walk through the supertraits to find + // those that do. + let candidates = traits::supertraits(tcx, trait_ref).filter(|r| { + self.trait_defines_associated_type_named(r.def_id(), binding.item_name) + }); + self.one_bound_for_assoc_type(candidates, &trait_ref.to_string(), + binding.item_name, binding.span) + }?; + + let (assoc_ident, def_scope) = tcx.adjust(binding.item_name, candidate.def_id(), ref_id); + let assoc_ty = tcx.associated_items(candidate.def_id()).find(|i| { + i.kind == ty::AssociatedKind::Type && i.name.to_ident() == assoc_ident + }).expect("missing associated type"); + + if !assoc_ty.vis.is_accessible_from(def_scope, tcx) { + let msg = format!("associated type `{}` is private", binding.item_name); + tcx.sess.span_err(binding.span, &msg); } - - // Otherwise, we have to walk through the supertraits to find - // those that do. - let candidates = - traits::supertraits(tcx, trait_ref.clone()) - .filter(|r| self.trait_defines_associated_type_named(r.def_id(), binding.item_name)); - - let candidate = self.one_bound_for_assoc_type(candidates, - &trait_ref.to_string(), - binding.item_name, - binding.span)?; + tcx.check_stability(assoc_ty.def_id, ref_id, binding.span); Ok(candidate.map_bound(|trait_ref| { ty::ProjectionPredicate { diff --git a/src/test/compile-fail/lint-stability-deprecated.rs b/src/test/compile-fail/lint-stability-deprecated.rs index df5c3dddcde3..f2defc1d421b 100644 --- a/src/test/compile-fail/lint-stability-deprecated.rs +++ b/src/test/compile-fail/lint-stability-deprecated.rs @@ -108,6 +108,11 @@ mod cross_crate { struct S1(T::TypeUnstable); struct S2(T::TypeDeprecated); //~^ WARN use of deprecated item 'lint_stability::TraitWithAssociatedTypes::TypeDeprecated': text + type A = TraitWithAssociatedTypes< + TypeUnstable = u8, + TypeDeprecated = u16, + //~^ WARN use of deprecated item 'lint_stability::TraitWithAssociatedTypes::TypeDeprecated' + >; let _ = DeprecatedStruct { //~ WARN use of deprecated item 'lint_stability::DeprecatedStruct' i: 0 //~ WARN use of deprecated item 'lint_stability::DeprecatedStruct::i' diff --git a/src/test/compile-fail/lint-stability.rs b/src/test/compile-fail/lint-stability.rs index 1ece7a0b8e33..49a52204295e 100644 --- a/src/test/compile-fail/lint-stability.rs +++ b/src/test/compile-fail/lint-stability.rs @@ -96,6 +96,10 @@ mod cross_crate { struct S1(T::TypeUnstable); //~^ ERROR use of unstable library feature struct S2(T::TypeDeprecated); + type A = TraitWithAssociatedTypes< + TypeUnstable = u8, //~ ERROR use of unstable library feature + TypeDeprecated = u16, + >; let _ = DeprecatedStruct { i: 0 diff --git a/src/test/compile-fail/trait-item-privacy.rs b/src/test/compile-fail/trait-item-privacy.rs index b8d83e5adf23..be0f7dd4e1cd 100644 --- a/src/test/compile-fail/trait-item-privacy.rs +++ b/src/test/compile-fail/trait-item-privacy.rs @@ -131,6 +131,16 @@ fn check_assoc_ty() { let _: T::A; //~ ERROR associated type `A` is private let _: T::B; // OK let _: T::C; // OK + + // Associated types, bindings + let _: assoc_ty::B< + B = u8, // OK + >; + let _: C< + A = u8, //~ ERROR associated type `A` is private + B = u8, // OK + C = u8, // OK + >; } fn main() {} From 190adc0e193d9b7154b54b4800e2059acb72448b Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 18 Nov 2017 18:49:37 +0300 Subject: [PATCH 3/5] Properly check traits in type privacy --- src/librustc/hir/mod.rs | 9 +- src/librustc_privacy/lib.rs | 88 +++++++++----- src/librustc_typeck/astconv.rs | 114 ++++++++++-------- src/librustc_typeck/lib.rs | 17 ++- .../associated-item-privacy-inherent.rs | 2 +- .../privacy/associated-item-privacy-trait.rs | 9 +- .../associated-item-privacy-type-binding.rs | 9 +- 7 files changed, 155 insertions(+), 93 deletions(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index dc44a943e4cf..3a6fabc33ab5 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -258,8 +258,13 @@ impl Path { impl fmt::Debug for Path { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "path({})", - print::to_string(print::NO_ANN, |s| s.print_path(self, false))) + write!(f, "path({})", print::to_string(print::NO_ANN, |s| s.print_path(self, false))) + } +} + +impl fmt::Display for Path { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", print::to_string(print::NO_ANN, |s| s.print_path(self, false))) } } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index d41881218129..906e584e0ecb 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -614,6 +614,7 @@ struct TypePrivacyVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, tables: &'a ty::TypeckTables<'tcx>, current_item: DefId, + in_body: bool, span: Span, empty_tables: &'a ty::TypeckTables<'tcx>, } @@ -671,10 +672,8 @@ impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> { // Take node ID of an expression or pattern and check its type for privacy. fn check_expr_pat_type(&mut self, id: hir::HirId, 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_id_to_type(id).visit_with(self) { + return true; } if self.tables.node_substs(id).visit_with(self) { return true; @@ -688,6 +687,16 @@ impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> { } false } + + 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> { @@ -699,16 +708,18 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { fn visit_nested_body(&mut self, body: hir::BodyId) { let orig_tables = replace(&mut self.tables, self.tcx.body_tables(body)); + let orig_in_body = replace(&mut self.in_body, true); let body = self.tcx.hir.body(body); self.visit_body(body); self.tables = orig_tables; + self.in_body = orig_in_body; } 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) { + if self.in_body { // Types in bodies. - if ty.visit_with(self) { + if self.tables.node_id_to_type(hir_ty.hir_id).visit_with(self) { return; } } else { @@ -724,10 +735,21 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { } 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; + self.span = trait_ref.path.span; + if !self.in_body { + // Avoid calling `hir_trait_to_predicates` in bodies, it will ICE. + // The traits' privacy in bodies is already checked as a part of trait object types. + let (principal, projections) = + rustc_typeck::hir_trait_to_predicates(self.tcx, trait_ref); + if self.check_trait_ref(*principal.skip_binder()) { + return; + } + for poly_predicate in projections { + let tcx = self.tcx; + if self.check_trait_ref(poly_predicate.skip_binder().projection_ty.trait_ref(tcx)) { + return; + } + } } intravisit::walk_trait_ref(self, trait_ref); @@ -760,19 +782,29 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { intravisit::walk_expr(self, expr); } + // Prohibit access to associated items with insufficient nominal visibility. 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 { - let hir_id = self.tcx.hir.node_to_hir_id(id); - if let Some(def) = self.tables.type_dependent_defs().get(hir_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; - } - } - } + let def = match *qpath { + hir::QPath::Resolved(_, ref path) => match path.def { + Def::Method(..) | Def::AssociatedConst(..) | + Def::AssociatedTy(..) => Some(path.def), + _ => None, + } + hir::QPath::TypeRelative(..) => { + let hir_id = self.tcx.hir.node_to_hir_id(id); + self.tables.type_dependent_defs().get(hir_id).cloned() + } + }; + if let Some(def) = def { + let def_id = def.def_id(); + if !self.item_is_accessible(def_id) { + let name = match *qpath { + hir::QPath::Resolved(_, ref path) => format!("{}", path), + hir::QPath::TypeRelative(_, ref segment) => segment.name.to_string(), + }; + let msg = format!("{} `{}` is private", def.kind_name(), name); + self.tcx.sess.span_err(span, &msg); + return; } } @@ -807,9 +839,11 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { item.id, &mut self.tables, self.empty_tables); + let orig_in_body = replace(&mut self.in_body, false); self.current_item = self.tcx.hir.local_def_id(item.id); intravisit::walk_item(self, item); self.tables = orig_tables; + self.in_body = orig_in_body; self.current_item = orig_current_item; } @@ -869,13 +903,8 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { } } ty::TyProjection(ref proj) => { - 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) { + let tcx = self.tcx; + if self.check_trait_ref(proj.trait_ref(tcx)) { return true; } } @@ -1629,6 +1658,7 @@ fn privacy_access_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx, tables: &empty_tables, current_item: DefId::local(CRATE_DEF_INDEX), + in_body: false, span: krate.span, empty_tables: &empty_tables, }; diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index ba0e79168922..cc79ae54c6bc 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -347,13 +347,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } } - pub fn instantiate_poly_trait_ref(&self, - ast_trait_ref: &hir::PolyTraitRef, + pub(super) fn instantiate_poly_trait_ref_inner(&self, + trait_ref: &hir::TraitRef, self_ty: Ty<'tcx>, - poly_projections: &mut Vec>) + poly_projections: &mut Vec>, + speculative: bool) -> ty::PolyTraitRef<'tcx> { - let trait_ref = &ast_trait_ref.trait_ref; let trait_def_id = self.trait_def_id(trait_ref); debug!("ast_path_to_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id); @@ -371,7 +371,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // specify type to assert that error was already reported in Err case: let predicate: Result<_, ErrorReported> = self.ast_type_binding_to_poly_projection_predicate(trait_ref.ref_id, poly_trait_ref, - binding); + binding, speculative); predicate.ok() // ok to ignore Err() because ErrorReported (see above) })); @@ -380,6 +380,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { poly_trait_ref } + pub fn instantiate_poly_trait_ref(&self, + poly_trait_ref: &hir::PolyTraitRef, + self_ty: Ty<'tcx>, + poly_projections: &mut Vec>) + -> ty::PolyTraitRef<'tcx> + { + self.instantiate_poly_trait_ref_inner(&poly_trait_ref.trait_ref, self_ty, + poly_projections, false) + } + fn ast_path_to_mono_trait_ref(&self, span: Span, trait_def_id: DefId, @@ -445,55 +455,59 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { &self, ref_id: ast::NodeId, trait_ref: ty::PolyTraitRef<'tcx>, - binding: &ConvertedBinding<'tcx>) + binding: &ConvertedBinding<'tcx>, + speculative: bool) -> Result, ErrorReported> { let tcx = self.tcx(); - // Given something like `U : SomeTrait`, we want to produce a - // predicate like `::T = X`. This is somewhat - // subtle in the event that `T` is defined in a supertrait of - // `SomeTrait`, because in that case we need to upcast. - // - // That is, consider this case: - // - // ``` - // trait SubTrait : SuperTrait { } - // trait SuperTrait { type T; } - // - // ... B : SubTrait ... - // ``` - // - // We want to produce `>::T == foo`. - - // Find any late-bound regions declared in `ty` that are not - // declared in the trait-ref. These are not wellformed. - // - // Example: - // - // for<'a> ::Item = &'a str // <-- 'a is bad - // for<'a> >::Output = &'a str // <-- 'a is ok - let late_bound_in_trait_ref = tcx.collect_constrained_late_bound_regions(&trait_ref); - let late_bound_in_ty = tcx.collect_referenced_late_bound_regions(&ty::Binder(binding.ty)); - debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref); - debug!("late_bound_in_ty = {:?}", late_bound_in_ty); - for br in late_bound_in_ty.difference(&late_bound_in_trait_ref) { - let br_name = match *br { - ty::BrNamed(_, name) => name, - _ => { - span_bug!( - binding.span, - "anonymous bound region {:?} in binding but not trait ref", - br); - } - }; - struct_span_err!(tcx.sess, - binding.span, - E0582, - "binding for associated type `{}` references lifetime `{}`, \ - which does not appear in the trait input types", - binding.item_name, br_name) - .emit(); + if !speculative { + // Given something like `U : SomeTrait`, we want to produce a + // predicate like `::T = X`. This is somewhat + // subtle in the event that `T` is defined in a supertrait of + // `SomeTrait`, because in that case we need to upcast. + // + // That is, consider this case: + // + // ``` + // trait SubTrait : SuperTrait { } + // trait SuperTrait { type T; } + // + // ... B : SubTrait ... + // ``` + // + // We want to produce `>::T == foo`. + + // Find any late-bound regions declared in `ty` that are not + // declared in the trait-ref. These are not wellformed. + // + // Example: + // + // for<'a> ::Item = &'a str // <-- 'a is bad + // for<'a> >::Output = &'a str // <-- 'a is ok + let late_bound_in_trait_ref = tcx.collect_constrained_late_bound_regions(&trait_ref); + let late_bound_in_ty = + tcx.collect_referenced_late_bound_regions(&ty::Binder(binding.ty)); + debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref); + debug!("late_bound_in_ty = {:?}", late_bound_in_ty); + for br in late_bound_in_ty.difference(&late_bound_in_trait_ref) { + let br_name = match *br { + ty::BrNamed(_, name) => name, + _ => { + span_bug!( + binding.span, + "anonymous bound region {:?} in binding but not trait ref", + br); + } + }; + struct_span_err!(tcx.sess, + binding.span, + E0582, + "binding for associated type `{}` references lifetime `{}`, \ + which does not appear in the trait input types", + binding.item_name, br_name) + .emit(); + } } let candidate = if self.trait_defines_associated_type_named(trait_ref.def_id(), diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index bf8f9d8b24a0..31f3b4e699af 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -348,7 +348,22 @@ pub fn hir_ty_to_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir_ty: &hir::Ty) -> let env_node_id = tcx.hir.get_parent(hir_ty.id); let env_def_id = tcx.hir.local_def_id(env_node_id); let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id); - item_cx.to_ty(hir_ty) + astconv::AstConv::ast_ty_to_ty(&item_cx, hir_ty) +} + +pub fn hir_trait_to_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir_trait: &hir::TraitRef) + -> (ty::PolyTraitRef<'tcx>, Vec>) { + // In case there are any projections etc, find the "environment" + // def-id that will be used to determine the traits/predicates in + // scope. This is derived from the enclosing item-like thing. + let env_node_id = tcx.hir.get_parent(hir_trait.ref_id); + let env_def_id = tcx.hir.local_def_id(env_node_id); + let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id); + let mut projections = Vec::new(); + let principal = astconv::AstConv::instantiate_poly_trait_ref_inner( + &item_cx, hir_trait, tcx.types.err, &mut projections, true + ); + (principal, projections) } __build_diagnostic_array! { librustc_typeck, DIAGNOSTICS } diff --git a/src/test/compile-fail/privacy/associated-item-privacy-inherent.rs b/src/test/compile-fail/privacy/associated-item-privacy-inherent.rs index d742a3a19422..63cb6e82c259 100644 --- a/src/test/compile-fail/privacy/associated-item-privacy-inherent.rs +++ b/src/test/compile-fail/privacy/associated-item-privacy-inherent.rs @@ -27,7 +27,7 @@ mod priv_nominal { Pub.method(); //~^ ERROR type `for<'r> fn(&'r priv_nominal::Pub) {priv_nominal::Pub::method}` is private Pub::CONST; - //FIXME ERROR associated constant `CONST` is private + //~^ ERROR associated constant `CONST` is private // let _: Pub::AssocTy; // pub type InSignatureTy = Pub::AssocTy; } diff --git a/src/test/compile-fail/privacy/associated-item-privacy-trait.rs b/src/test/compile-fail/privacy/associated-item-privacy-trait.rs index d68c50228490..bdc0c680a92b 100644 --- a/src/test/compile-fail/privacy/associated-item-privacy-trait.rs +++ b/src/test/compile-fail/privacy/associated-item-privacy-trait.rs @@ -31,17 +31,16 @@ mod priv_trait { Pub.method(); //~^ ERROR type `for<'r> fn(&'r Self) {::method}` is private ::CONST; - //FIXME ERROR associated constant `path(PrivTr::CONST)` is private + //~^ ERROR associated constant `PrivTr::CONST` is private let _: ::AssocTy; //~^ ERROR trait `priv_trait::PrivTr` is private //~| ERROR trait `priv_trait::PrivTr` is private pub type InSignatureTy = ::AssocTy; //~^ ERROR trait `priv_trait::PrivTr` is private - //~| ERROR trait `path(PrivTr)` is private pub trait InSignatureTr: PrivTr {} - //FIXME ERROR trait `priv_trait::PrivTr` is private + //~^ ERROR trait `priv_trait::PrivTr` is private impl PrivTr for u8 {} - //FIXME ERROR trait `priv_trait::PrivTr` is private + //~^ ERROR trait `priv_trait::PrivTr` is private } } fn priv_trait() { @@ -142,7 +141,7 @@ mod priv_parent_substs { pub type InSignatureTy2 = >::AssocTy; //~^ ERROR type `priv_parent_substs::Priv` is private impl PubTr for u8 {} - //FIXME ERROR type `priv_parent_substs::Priv` is private + //~^ ERROR type `priv_parent_substs::Priv` is private } } fn priv_parent_substs() { diff --git a/src/test/compile-fail/privacy/associated-item-privacy-type-binding.rs b/src/test/compile-fail/privacy/associated-item-privacy-type-binding.rs index f191ff14dce6..c25616c54354 100644 --- a/src/test/compile-fail/privacy/associated-item-privacy-type-binding.rs +++ b/src/test/compile-fail/privacy/associated-item-privacy-type-binding.rs @@ -24,7 +24,7 @@ mod priv_trait { type InSignatureTy2 = Box>; //~^ ERROR type `priv_trait::PubTr + 'static` is private trait InSignatureTr2: PubTr {} - //FIXME ERROR trait `priv_trait::PrivTr` is private + //~^ ERROR trait `priv_trait::PrivTr` is private } pub macro mac2() { let _: Box>; @@ -32,9 +32,8 @@ mod priv_trait { //~| ERROR type `priv_trait::PrivTr + '` is private type InSignatureTy1 = Box>; //~^ ERROR type `priv_trait::PrivTr + 'static` is private - //~| ERROR trait `path(PrivTr)` is private trait InSignatureTr1: PrivTr {} - //FIXME ERROR trait `priv_trait::PrivTr` is private + //~^ ERROR trait `priv_trait::PrivTr` is private } } fn priv_trait1() { @@ -63,9 +62,9 @@ mod priv_parent_substs { pub type InSignatureTy2 = Box>; //~^ ERROR type `priv_parent_substs::Priv` is private trait InSignatureTr1: PubTrWithParam {} - //FIXME ERROR type `priv_parent_substs::Priv` is private + //~^ ERROR type `priv_parent_substs::Priv` is private trait InSignatureTr2: PubTr {} - //FIXME ERROR type `priv_parent_substs::Priv` is private + //~^ ERROR type `priv_parent_substs::Priv` is private } } fn priv_parent_substs() { From 020961d88027faf901c533634f07bb5bf3bb64d3 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 18 Nov 2017 19:15:16 +0300 Subject: [PATCH 4/5] Prohibit access to private statics from other crates through macros 2.0 --- src/librustc_privacy/lib.rs | 10 ++++++++-- .../compile-fail/auxiliary/private-inferred-type.rs | 2 ++ src/test/compile-fail/private-inferred-type-3.rs | 1 + src/test/compile-fail/private-inferred-type.rs | 2 ++ 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 906e584e0ecb..fc2e2ca66203 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -783,11 +783,16 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { } // Prohibit access to associated items with insufficient nominal visibility. + // + // Additionally, until better reachability analysis for macros 2.0 is available, + // we prohibit access to private statics from other crates, this allows to give + // more code internal visibility at link time. (Access to private functions + // is already prohibited by type privacy for funciton types.) fn visit_qpath(&mut self, qpath: &'tcx hir::QPath, id: ast::NodeId, span: Span) { let def = match *qpath { hir::QPath::Resolved(_, ref path) => match path.def { Def::Method(..) | Def::AssociatedConst(..) | - Def::AssociatedTy(..) => Some(path.def), + Def::AssociatedTy(..) | Def::Static(..) => Some(path.def), _ => None, } hir::QPath::TypeRelative(..) => { @@ -797,7 +802,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> { }; if let Some(def) = def { let def_id = def.def_id(); - if !self.item_is_accessible(def_id) { + let is_local_static = if let Def::Static(..) = def { def_id.is_local() } else { false }; + if !self.item_is_accessible(def_id) && !is_local_static { let name = match *qpath { hir::QPath::Resolved(_, ref path) => format!("{}", path), hir::QPath::TypeRelative(_, ref segment) => segment.name.to_string(), diff --git a/src/test/compile-fail/auxiliary/private-inferred-type.rs b/src/test/compile-fail/auxiliary/private-inferred-type.rs index 7627f5dc0cd0..fc43765f63ce 100644 --- a/src/test/compile-fail/auxiliary/private-inferred-type.rs +++ b/src/test/compile-fail/auxiliary/private-inferred-type.rs @@ -11,6 +11,7 @@ #![feature(decl_macro)] fn priv_fn() {} +static PRIV_STATIC: u8 = 0; enum PrivEnum { Variant } pub enum PubEnum { Variant } trait PrivTrait { fn method() {} } @@ -34,6 +35,7 @@ impl Pub { pub macro m() { priv_fn; + PRIV_STATIC; PrivEnum::Variant; PubEnum::Variant; ::method; diff --git a/src/test/compile-fail/private-inferred-type-3.rs b/src/test/compile-fail/private-inferred-type-3.rs index c0ba38b24020..0c393f02323e 100644 --- a/src/test/compile-fail/private-inferred-type-3.rs +++ b/src/test/compile-fail/private-inferred-type-3.rs @@ -11,6 +11,7 @@ // aux-build:private-inferred-type.rs // error-pattern:type `fn() {ext::priv_fn}` is private +// error-pattern:static `PRIV_STATIC` 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 diff --git a/src/test/compile-fail/private-inferred-type.rs b/src/test/compile-fail/private-inferred-type.rs index 95e3732d6134..c50d7f59b8e0 100644 --- a/src/test/compile-fail/private-inferred-type.rs +++ b/src/test/compile-fail/private-inferred-type.rs @@ -15,6 +15,7 @@ mod m { fn priv_fn() {} + static PRIV_STATIC: u8 = 0; enum PrivEnum { Variant } pub enum PubEnum { Variant } trait PrivTrait { fn method() {} } @@ -47,6 +48,7 @@ mod m { pub macro m() { priv_fn; //~ ERROR type `fn() {m::priv_fn}` is private + PRIV_STATIC; // OK, not cross-crate PrivEnum::Variant; //~ ERROR type `m::PrivEnum` is private PubEnum::Variant; // OK ::method; //~ ERROR type `fn() {::method}` is private From c6209a36bbef743a25f3823e1ab387080a4f307c Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 18 Nov 2017 20:32:24 +0300 Subject: [PATCH 5/5] Always report private-in-public in associated types as hard errors according to RFC 2145. Fix a silly label message. --- src/librustc_privacy/lib.rs | 21 +++++---- src/test/compile-fail/E0445.rs | 3 ++ src/test/compile-fail/issue-30079.rs | 7 +-- .../private-in-public-assoc-ty.rs | 43 ++++++++++++++++++ .../private-in-public-ill-formed.rs | 45 +++++++++++++++++++ .../compile-fail/private-in-public-warn.rs | 15 ------- .../compile-fail/private-inferred-type.rs | 5 ++- 7 files changed, 108 insertions(+), 31 deletions(-) create mode 100644 src/test/compile-fail/private-in-public-assoc-ty.rs create mode 100644 src/test/compile-fail/private-in-public-ill-formed.rs diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index fc2e2ca66203..5b277402f1e0 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -1313,6 +1313,7 @@ struct SearchInterfaceForPrivateItemsVisitor<'a, 'tcx: 'a> { min_visibility: ty::Visibility, has_pub_restricted: bool, has_old_errors: bool, + in_assoc_ty: bool, } impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> { @@ -1373,11 +1374,11 @@ impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> { self.min_visibility = vis; } if !vis.is_at_least(self.required_visibility, self.tcx) { - if self.has_pub_restricted || self.has_old_errors { + if self.has_pub_restricted || self.has_old_errors || self.in_assoc_ty { struct_span_err!(self.tcx.sess, self.span, E0445, "private trait `{}` in public interface", trait_ref) .span_label(self.span, format!( - "private trait can't be public")) + "can't leak private trait")) .emit(); } else { self.tcx.lint_node(lint::builtin::PRIVATE_IN_PUBLIC, @@ -1428,7 +1429,7 @@ impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<' self.min_visibility = vis; } if !vis.is_at_least(self.required_visibility, self.tcx) { - if self.has_pub_restricted || self.has_old_errors { + if self.has_pub_restricted || self.has_old_errors || self.in_assoc_ty { let mut err = struct_span_err!(self.tcx.sess, self.span, E0446, "private type `{}` in public interface", ty); err.span_label(self.span, "can't leak private type"); @@ -1489,6 +1490,7 @@ impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> { required_visibility, has_pub_restricted: self.has_pub_restricted, has_old_errors, + in_assoc_ty: false, } } } @@ -1529,6 +1531,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> for trait_item_ref in trait_item_refs { let mut check = self.check(trait_item_ref.id.node_id, item_visibility); + check.in_assoc_ty = trait_item_ref.kind == hir::AssociatedItemKind::Type; check.generics().predicates(); if trait_item_ref.kind == hir::AssociatedItemKind::Type && @@ -1579,10 +1582,10 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> for impl_item_ref in impl_item_refs { let impl_item = self.tcx.hir.impl_item(impl_item_ref.id); - let impl_item_vis = - ty::Visibility::from_hir(&impl_item.vis, item.id, tcx); - self.check(impl_item.id, min(impl_item_vis, ty_vis)) - .generics().predicates().ty(); + let impl_item_vis = ty::Visibility::from_hir(&impl_item.vis, item.id, tcx); + let mut check = self.check(impl_item.id, min(impl_item_vis, ty_vis)); + check.in_assoc_ty = impl_item_ref.kind == hir::AssociatedItemKind::Type; + check.generics().predicates().ty(); // Recurse for e.g. `impl Trait` (see `visit_ty`). self.inner_visibility = impl_item_vis; @@ -1597,7 +1600,9 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> self.check(item.id, vis).generics().predicates(); for impl_item_ref in impl_item_refs { let impl_item = self.tcx.hir.impl_item(impl_item_ref.id); - self.check(impl_item.id, vis).generics().predicates().ty(); + let mut check = self.check(impl_item.id, vis); + check.in_assoc_ty = impl_item_ref.kind == hir::AssociatedItemKind::Type; + check.generics().predicates().ty(); // Recurse for e.g. `impl Trait` (see `visit_ty`). self.inner_visibility = vis; diff --git a/src/test/compile-fail/E0445.rs b/src/test/compile-fail/E0445.rs index a1447e7ebcdd..bca1b52d17a9 100644 --- a/src/test/compile-fail/E0445.rs +++ b/src/test/compile-fail/E0445.rs @@ -14,9 +14,12 @@ trait Foo { pub trait Bar : Foo {} //~^ ERROR private trait `Foo` in public interface [E0445] +//~| NOTE can't leak private trait pub struct Bar2(pub T); //~^ ERROR private trait `Foo` in public interface [E0445] +//~| NOTE can't leak private trait pub fn foo (t: T) {} //~^ ERROR private trait `Foo` in public interface [E0445] +//~| NOTE can't leak private trait fn main() {} diff --git a/src/test/compile-fail/issue-30079.rs b/src/test/compile-fail/issue-30079.rs index 15b7edb32d41..04ae8f6d255d 100644 --- a/src/test/compile-fail/issue-30079.rs +++ b/src/test/compile-fail/issue-30079.rs @@ -8,15 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(private_in_public)] -#![allow(unused)] - struct SemiPriv; mod m1 { struct Priv; impl ::SemiPriv { - pub fn f(_: Priv) {} //~ ERROR private type `m1::Priv` in public interface + pub fn f(_: Priv) {} //~ WARN private type `m1::Priv` in public interface //~^ WARNING hard error } @@ -29,7 +26,6 @@ mod m2 { struct Priv; impl ::std::ops::Deref for ::SemiPriv { type Target = Priv; //~ ERROR private type `m2::Priv` in public interface - //~^ WARNING hard error fn deref(&self) -> &Self::Target { unimplemented!() } } @@ -47,7 +43,6 @@ mod m3 { struct Priv; impl ::SemiPrivTrait for () { type Assoc = Priv; //~ ERROR private type `m3::Priv` in public interface - //~^ WARNING hard error } } diff --git a/src/test/compile-fail/private-in-public-assoc-ty.rs b/src/test/compile-fail/private-in-public-assoc-ty.rs new file mode 100644 index 000000000000..59dee2566425 --- /dev/null +++ b/src/test/compile-fail/private-in-public-assoc-ty.rs @@ -0,0 +1,43 @@ +// 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. + +// Private types and traits are not allowed in interfaces of associated types. +// This test also ensures that the checks are performed even inside private modules. + +#![feature(associated_type_defaults)] + +mod m { + struct Priv; + trait PrivTr {} + impl PrivTr for Priv {} + pub trait PubTrAux1 {} + pub trait PubTrAux2 { type A; } + + // "Private-in-public in associated types is hard error" in RFC 2145 + // applies only to the aliased types, not bounds. + pub trait PubTr { + //~^ WARN private trait `m::PrivTr` in public interface + //~| WARN this was previously accepted + //~| WARN private type `m::Priv` in public interface + //~| WARN this was previously accepted + type Alias1: PrivTr; + type Alias2: PubTrAux1 = u8; + type Alias3: PubTrAux2 = u8; + + type Alias4 = Priv; + //~^ ERROR private type `m::Priv` in public interface + } + impl PubTr for u8 { + type Alias1 = Priv; + //~^ ERROR private type `m::Priv` in public interface + } +} + +fn main() {} diff --git a/src/test/compile-fail/private-in-public-ill-formed.rs b/src/test/compile-fail/private-in-public-ill-formed.rs new file mode 100644 index 000000000000..4e10614bf62c --- /dev/null +++ b/src/test/compile-fail/private-in-public-ill-formed.rs @@ -0,0 +1,45 @@ +// 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. + +mod aliases_pub { + struct Priv; + mod m { + pub struct Pub3; + } + + trait PrivTr { + type AssocAlias; + } + impl PrivTr for Priv { + type AssocAlias = m::Pub3; + } + + impl (::AssocAlias) { //~ ERROR no base type found for inherent implementation + pub fn f(arg: Priv) {} // private type `aliases_pub::Priv` in public interface + } +} + +mod aliases_priv { + struct Priv; + struct Priv3; + + trait PrivTr { + type AssocAlias; + } + impl PrivTr for Priv { + type AssocAlias = Priv3; + } + + impl (::AssocAlias) { //~ ERROR no base type found for inherent implementation + pub fn f(arg: Priv) {} // OK + } +} + +fn main() {} diff --git a/src/test/compile-fail/private-in-public-warn.rs b/src/test/compile-fail/private-in-public-warn.rs index f030012b172f..dfcf4dc01b8a 100644 --- a/src/test/compile-fail/private-in-public-warn.rs +++ b/src/test/compile-fail/private-in-public-warn.rs @@ -13,7 +13,6 @@ #![feature(associated_type_defaults)] #![deny(private_in_public)] -#![allow(unused)] #![allow(improper_ctypes)] mod types { @@ -35,7 +34,6 @@ mod types { const C: Priv = Priv; //~ ERROR private type `types::Priv` in public interface //~^ WARNING hard error type Alias = Priv; //~ ERROR private type `types::Priv` in public interface - //~^ WARNING hard error fn f1(arg: Priv) {} //~ ERROR private type `types::Priv` in public interface //~^ WARNING hard error fn f2() -> Priv { panic!() } //~ ERROR private type `types::Priv` in public interface @@ -51,7 +49,6 @@ mod types { } impl PubTr for Pub { type Alias = Priv; //~ ERROR private type `types::Priv` in public interface - //~^ WARNING hard error } } @@ -146,7 +143,6 @@ mod impls { } impl PubTr for Pub { type Alias = Priv; //~ ERROR private type `impls::Priv` in public interface - //~^ WARNING hard error } } @@ -220,21 +216,14 @@ mod aliases_pub { pub fn f(arg: Priv) {} //~ ERROR private type `aliases_pub::Priv` in public interface //~^ WARNING hard error } - // This doesn't even parse - // impl ::AssocAlias { - // pub fn f(arg: Priv) {} // ERROR private type `aliases_pub::Priv` in public interface - // } impl PrivUseAliasTr for PrivUseAlias { type Check = Priv; //~ ERROR private type `aliases_pub::Priv` in public interface - //~^ WARNING hard error } impl PrivUseAliasTr for PrivAlias { type Check = Priv; //~ ERROR private type `aliases_pub::Priv` in public interface - //~^ WARNING hard error } impl PrivUseAliasTr for ::AssocAlias { type Check = Priv; //~ ERROR private type `aliases_pub::Priv` in public interface - //~^ WARNING hard error } } @@ -273,10 +262,6 @@ mod aliases_priv { impl PrivAlias { pub fn f(arg: Priv) {} // OK } - // This doesn't even parse - // impl ::AssocAlias { - // pub fn f(arg: Priv) {} // OK - // } impl PrivUseAliasTr for PrivUseAlias { type Check = Priv; // OK } diff --git a/src/test/compile-fail/private-inferred-type.rs b/src/test/compile-fail/private-inferred-type.rs index c50d7f59b8e0..351dc6b776b2 100644 --- a/src/test/compile-fail/private-inferred-type.rs +++ b/src/test/compile-fail/private-inferred-type.rs @@ -11,7 +11,7 @@ #![feature(associated_consts)] #![feature(conservative_impl_trait)] #![feature(decl_macro)] -#![allow(warnings)] +#![allow(private_in_public)] mod m { fn priv_fn() {} @@ -70,6 +70,7 @@ mod m { impl TraitWithTyParam for u8 {} impl TraitWithTyParam2 for u8 {} impl TraitWithAssocTy for u8 { type AssocTy = Priv; } + //~^ ERROR private type `m::Priv` in public interface pub fn leak_anon1() -> impl Trait + 'static { 0 } pub fn leak_anon2() -> impl TraitWithTyParam { 0 } @@ -90,7 +91,7 @@ mod adjust { pub struct S3; impl Deref for S1 { - type Target = S2Alias; + type Target = S2Alias; //~ ERROR private type `adjust::S2` in public interface fn deref(&self) -> &Self::Target { loop {} } } impl Deref for S2 {