Always report private-in-public in associated types as hard errors

according to RFC 2145.

Fix a silly label message.
This commit is contained in:
Vadim Petrochenkov 2017-11-18 20:32:24 +03:00
parent 020961d880
commit c6209a36bb
7 changed files with 108 additions and 31 deletions

View File

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

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

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

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