Skip to content

Commit

Permalink
Always report private-in-public in associated types as hard errors
Browse files Browse the repository at this point in the history
according to RFC 2145.

Fix a silly label message.
  • Loading branch information
petrochenkov committed Dec 21, 2017
1 parent 020961d commit c6209a3
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 31 deletions.
21 changes: 13 additions & 8 deletions src/librustc_privacy/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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,
}
}
}
Expand Down Expand Up @@ -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 &&
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions src/test/compile-fail/E0445.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {}
7 changes: 1 addition & 6 deletions src/test/compile-fail/issue-30079.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand All @@ -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!() }
}

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

Expand Down
43 changes: 43 additions & 0 deletions src/test/compile-fail/private-in-public-assoc-ty.rs
Original file line number Diff line number Diff line change
@@ -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() {}
45 changes: 45 additions & 0 deletions src/test/compile-fail/private-in-public-ill-formed.rs
Original file line number Diff line number Diff line change
@@ -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() {}
15 changes: 0 additions & 15 deletions src/test/compile-fail/private-in-public-warn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

#![feature(associated_type_defaults)]
#![deny(private_in_public)]
#![allow(unused)]
#![allow(improper_ctypes)]

mod types {
Expand All @@ -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
Expand All @@ -51,7 +49,6 @@ mod types {
}
impl PubTr for Pub {
type Alias = Priv; //~ ERROR private type `types::Priv` in public interface
//~^ WARNING hard error
}
}

Expand Down Expand Up @@ -146,7 +143,6 @@ mod impls {
}
impl PubTr for Pub {
type Alias = Priv; //~ ERROR private type `impls::Priv` in public interface
//~^ WARNING hard error
}
}

Expand Down Expand Up @@ -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
}
}

Expand Down Expand Up @@ -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
}
Expand Down
5 changes: 3 additions & 2 deletions src/test/compile-fail/private-inferred-type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {}
Expand Down Expand Up @@ -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 }
Expand All @@ -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 {
Expand Down

0 comments on commit c6209a3

Please sign in to comment.