Auto merge of #46083 - petrochenkov:morepriv, r=nikomatsakis

Type privacy polishing

Various preparations before implementing https://github.com/rust-lang/rfcs/pull/2145 containing final minor breaking changes (mostly for unstable code or code using `allow(private_in_public)`).
(Continuation of https://github.com/rust-lang/rust/pull/42125, https://github.com/rust-lang/rust/pull/44633 and https://github.com/rust-lang/rust/pull/41332.)

It would be good to run crater on this.
r? @eddyb
This commit is contained in:
bors 2017-12-21 02:48:17 +00:00
commit a12706ca71
18 changed files with 655 additions and 135 deletions

View file

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

View file

@ -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,35 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
intravisit::walk_expr(self, expr);
}
// 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) {
// 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(..) | Def::Static(..) => 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();
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(),
};
let msg = format!("{} `{}` is private", def.kind_name(), name);
self.tcx.sess.span_err(span, &msg);
return;
}
}
@ -807,9 +845,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 +909,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;
}
}
@ -1278,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> {
@ -1338,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,
@ -1393,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");
@ -1454,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,
}
}
}
@ -1494,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 &&
@ -1544,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;
@ -1562,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;
@ -1629,6 +1669,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,
};

View file

@ -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<ty::PolyProjectionPredicate<'tcx>>)
poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>,
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);
@ -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, speculative);
predicate.ok() // ok to ignore Err() because ErrorReported (see above)
}));
@ -379,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::PolyProjectionPredicate<'tcx>>)
-> 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,
@ -442,82 +453,87 @@ 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>)
binding: &ConvertedBinding<'tcx>,
speculative: bool)
-> Result<ty::PolyProjectionPredicate<'tcx>, ErrorReported>
{
let tcx = self.tcx();
// Given something like `U : SomeTrait<T=X>`, we want to produce a
// predicate like `<U as SomeTrait>::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<int> { }
// trait SuperTrait<A> { type T; }
//
// ... B : SubTrait<T=foo> ...
// ```
//
// We want to produce `<B as SuperTrait<int>>::T == foo`.
if !speculative {
// Given something like `U : SomeTrait<T=X>`, we want to produce a
// predicate like `<U as SomeTrait>::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<int> { }
// trait SuperTrait<A> { type T; }
//
// ... B : SubTrait<T=foo> ...
// ```
//
// We want to produce `<B as SuperTrait<int>>::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> <T as Iterator>::Item = &'a str // <-- 'a is bad
// for<'a> <T as FnMut<(&'a u32,)>>::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();
// Find any late-bound regions declared in `ty` that are not
// declared in the trait-ref. These are not wellformed.
//
// Example:
//
// for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
// for<'a> <T as FnMut<(&'a u32,)>>::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();
}
}
// 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 {

View file

@ -349,7 +349,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<ty::PolyProjectionPredicate<'tcx>>) {
// 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 }

View file

@ -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<T: Foo>(pub T);
//~^ ERROR private trait `Foo` in public interface [E0445]
//~| NOTE can't leak private trait
pub fn foo<T: Foo> (t: T) {}
//~^ ERROR private trait `Foo` in public interface [E0445]
//~| NOTE can't leak private trait
fn main() {}

View file

@ -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<u8> {
pub macro m() {
priv_fn;
PRIV_STATIC;
PrivEnum::Variant;
PubEnum::Variant;
<u8 as PrivTrait>::method;

View file

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

View file

@ -108,6 +108,11 @@ mod cross_crate {
struct S1<T: TraitWithAssociatedTypes>(T::TypeUnstable);
struct S2<T: TraitWithAssociatedTypes>(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'

View file

@ -96,6 +96,10 @@ mod cross_crate {
struct S1<T: TraitWithAssociatedTypes>(T::TypeUnstable);
//~^ ERROR use of unstable library feature
struct S2<T: TraitWithAssociatedTypes>(T::TypeDeprecated);
type A = TraitWithAssociatedTypes<
TypeUnstable = u8, //~ ERROR use of unstable library feature
TypeDeprecated = u16,
>;
let _ = DeprecatedStruct {
i: 0

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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;
//~^ 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<T>(&self) {}
}
pub macro mac() {
let value = Pub::method::<Priv>;
//~^ ERROR type `priv_substs::Priv` is private
value;
//~^ ERROR type `priv_substs::Priv` is private
Pub.method::<Priv>();
//~^ ERROR type `priv_substs::Priv` is private
}
}
fn priv_substs() {
priv_substs::mac!();
}
mod priv_parent_substs {
struct Priv;
pub struct Pub<T = Priv>(T);
impl Pub<Priv> {
pub fn method(&self) {}
pub fn static_method() {}
pub const CONST: u8 = 0;
// pub type AssocTy = u8;
}
pub macro mac() {
let value = <Pub>::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 = <Pub>::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
<Pub>::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() {}

View file

@ -0,0 +1,151 @@
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 = <Pub as PrivTr>::method;
//~^ ERROR type `for<'r> fn(&'r priv_trait::Pub) {<priv_trait::Pub as priv_trait::PrivTr>::method}` is private
value;
//~^ ERROR type `for<'r> fn(&'r priv_trait::Pub) {<priv_trait::Pub as priv_trait::PrivTr>::method}` is private
Pub.method();
//~^ ERROR type `for<'r> fn(&'r Self) {<Self as priv_trait::PrivTr>::method}` is private
<Pub as PrivTr>::CONST;
//~^ ERROR associated constant `PrivTr::CONST` is private
let _: <Pub as PrivTr>::AssocTy;
//~^ ERROR trait `priv_trait::PrivTr` is private
//~| ERROR trait `priv_trait::PrivTr` is private
pub type InSignatureTy = <Pub as PrivTr>::AssocTy;
//~^ ERROR trait `priv_trait::PrivTr` is private
pub trait InSignatureTr: PrivTr {}
//~^ ERROR trait `priv_trait::PrivTr` is private
impl PrivTr for u8 {}
//~^ 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 = <Pub as PubTr>::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<T>(&self) {}
}
struct Priv;
pub struct Pub;
impl PubTr for Pub {}
pub macro mac() {
let value = <Pub as PubTr>::method::<Priv>;
//~^ ERROR type `priv_substs::Priv` is private
value;
//~^ ERROR type `priv_substs::Priv` is private
Pub.method::<Priv>();
//~^ ERROR type `priv_substs::Priv` is private
}
}
fn priv_substs() {
priv_substs::mac!();
}
mod priv_parent_substs {
pub trait PubTr<T = Priv> {
fn method(&self) {}
const CONST: u8 = 0;
type AssocTy = u8;
}
struct Priv;
pub struct Pub;
impl PubTr<Priv> for Pub {}
impl PubTr<Pub> for Priv {}
pub macro mac() {
let value = <Pub as PubTr>::method;
//~^ ERROR type `priv_parent_substs::Priv` is private
value;
//~^ ERROR type `priv_parent_substs::Priv` is private
let value = <Pub as PubTr<_>>::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 = <Priv as PubTr<_>>::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
<Pub as PubTr>::CONST;
//~^ ERROR type `priv_parent_substs::Priv` is private
<Pub as PubTr<_>>::CONST;
//~^ ERROR type `priv_parent_substs::Priv` is private
<Priv as PubTr<_>>::CONST;
//~^ ERROR type `priv_parent_substs::Priv` is private
let _: <Pub as PubTr>::AssocTy;
//~^ ERROR type `priv_parent_substs::Priv` is private
//~| ERROR type `priv_parent_substs::Priv` is private
let _: <Pub as PubTr<_>>::AssocTy;
//~^ ERROR type `priv_parent_substs::Priv` is private
//~| ERROR type `priv_parent_substs::Priv` is private
let _: <Priv as PubTr<_>>::AssocTy;
//~^ ERROR type `priv_parent_substs::Priv` is private
//~| ERROR type `priv_parent_substs::Priv` is private
pub type InSignatureTy1 = <Pub as PubTr>::AssocTy;
//~^ ERROR type `priv_parent_substs::Priv` is private
pub type InSignatureTy2 = <Priv as PubTr<Pub>>::AssocTy;
//~^ ERROR type `priv_parent_substs::Priv` is private
impl PubTr for u8 {}
//~^ ERROR type `priv_parent_substs::Priv` is private
}
}
fn priv_parent_substs() {
priv_parent_substs::mac!();
}
fn main() {}

View file

@ -0,0 +1,74 @@
// 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<PubTr<AssocTy = u8>>;
//~^ ERROR type `priv_trait::PubTr<AssocTy=u8> + '<empty>` is private
//~| ERROR type `priv_trait::PubTr<AssocTy=u8> + '<empty>` is private
type InSignatureTy2 = Box<PubTr<AssocTy = u8>>;
//~^ ERROR type `priv_trait::PubTr<AssocTy=u8> + 'static` is private
trait InSignatureTr2: PubTr<AssocTy = u8> {}
//~^ ERROR trait `priv_trait::PrivTr` is private
}
pub macro mac2() {
let _: Box<PrivTr<AssocTy = u8>>;
//~^ ERROR type `priv_trait::PrivTr<AssocTy=u8> + '<empty>` is private
//~| ERROR type `priv_trait::PrivTr<AssocTy=u8> + '<empty>` is private
type InSignatureTy1 = Box<PrivTr<AssocTy = u8>>;
//~^ ERROR type `priv_trait::PrivTr<AssocTy=u8> + 'static` is private
trait InSignatureTr1: PrivTr<AssocTy = u8> {}
//~^ 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<T = Priv> {
type AssocTy = u8;
}
struct Priv;
pub trait PubTr: PubTrWithParam<Priv> {}
pub macro mac() {
let _: Box<PubTrWithParam<AssocTy = u8>>;
//~^ ERROR type `priv_parent_substs::Priv` is private
//~| ERROR type `priv_parent_substs::Priv` is private
let _: Box<PubTr<AssocTy = u8>>;
//~^ ERROR type `priv_parent_substs::Priv` is private
//~| ERROR type `priv_parent_substs::Priv` is private
pub type InSignatureTy1 = Box<PubTrWithParam<AssocTy = u8>>;
//~^ ERROR type `priv_parent_substs::Priv` is private
pub type InSignatureTy2 = Box<PubTr<AssocTy = u8>>;
//~^ ERROR type `priv_parent_substs::Priv` is private
trait InSignatureTr1: PubTrWithParam<AssocTy = u8> {}
//~^ ERROR type `priv_parent_substs::Priv` is private
trait InSignatureTr2: PubTr<AssocTy = u8> {}
//~^ ERROR type `priv_parent_substs::Priv` is private
}
}
fn priv_parent_substs() {
priv_parent_substs::mac!();
}
fn main() {}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<T> {}
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<Priv> = u8;
type Alias3: PubTrAux2<A = Priv> = 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() {}

View file

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 (<Priv as PrivTr>::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 (<Priv as PrivTr>::AssocAlias) { //~ ERROR no base type found for inherent implementation
pub fn f(arg: Priv) {} // OK
}
}
fn main() {}

View file

@ -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 <Priv as PrivTr>::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 <Priv as PrivTr>::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 <Priv as PrivTr>::AssocAlias {
// pub fn f(arg: Priv) {} // OK
// }
impl PrivUseAliasTr for PrivUseAlias {
type Check = Priv; // OK
}

View file

@ -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() {<u8 as ext::PrivTrait>::method}` is private
// error-pattern:type `fn(u8) -> ext::PrivTupleStruct {ext::PrivTupleStruct::{{constructor}}}` is pr

View file

@ -11,10 +11,11 @@
#![feature(associated_consts)]
#![feature(conservative_impl_trait)]
#![feature(decl_macro)]
#![allow(warnings)]
#![allow(private_in_public)]
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
<u8 as PrivTrait>::method; //~ ERROR type `fn() {<u8 as m::PrivTrait>::method}` is private
@ -68,6 +70,7 @@ mod m {
impl<T> TraitWithTyParam<T> for u8 {}
impl TraitWithTyParam2<Priv> 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<Alias> { 0 }
@ -88,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 {

View file

@ -131,6 +131,16 @@ fn check_assoc_ty<T: assoc_ty::C>() {
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() {}