From d34b3e9bf2becb8fe8184559e2a376d1e7ab1fa3 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 16 Jan 2019 01:47:49 +0300 Subject: [PATCH] privacy: Account for associated existential types --- src/librustc_privacy/lib.rs | 43 +++++++++++-------- .../ui/privacy/private-in-public-assoc-ty.rs | 9 +++- .../privacy/private-in-public-assoc-ty.stderr | 20 ++++++--- .../privacy/private-in-public-existential.rs | 10 +++++ 4 files changed, 59 insertions(+), 23 deletions(-) diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 4890369e13f20..c0d7248fab7f3 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -13,7 +13,7 @@ extern crate rustc_typeck; extern crate syntax_pos; extern crate rustc_data_structures; -use rustc::hir::{self, Node, PatKind}; +use rustc::hir::{self, Node, PatKind, AssociatedItemKind}; use rustc::hir::def::Def; use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, CrateNum, DefId}; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; @@ -548,7 +548,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> { let mut reach = self.reach(trait_item_ref.id.node_id, item_level); reach.generics().predicates(); - if trait_item_ref.kind == hir::AssociatedItemKind::Type && + if trait_item_ref.kind == AssociatedItemKind::Type && !trait_item_ref.defaultness.has_value() { // No type to visit. } else { @@ -1333,11 +1333,11 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { if self.item_is_public(&impl_item_ref.id.node_id, &impl_item_ref.vis) { let impl_item = self.tcx.hir().impl_item(impl_item_ref.id); match impl_item_ref.kind { - hir::AssociatedItemKind::Const => { + AssociatedItemKind::Const => { found_pub_static = true; intravisit::walk_impl_item(self, impl_item); } - hir::AssociatedItemKind::Method { has_self: false } => { + AssociatedItemKind::Method { has_self: false } => { found_pub_static = true; intravisit::walk_impl_item(self, impl_item); } @@ -1558,6 +1558,24 @@ impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> { in_assoc_ty: false, } } + + fn check_trait_or_impl_item(&self, node_id: ast::NodeId, assoc_item_kind: AssociatedItemKind, + defaultness: hir::Defaultness, vis: ty::Visibility) { + let mut check = self.check(node_id, vis); + + let (check_ty, is_assoc_ty) = match assoc_item_kind { + AssociatedItemKind::Const | AssociatedItemKind::Method { .. } => (true, false), + AssociatedItemKind::Type => (defaultness.has_value(), true), + // `ty()` for existential types is the underlying type, + // it's not a part of interface, so we skip it. + AssociatedItemKind::Existential => (false, true), + }; + check.in_assoc_ty = is_assoc_ty; + check.generics().predicates(); + if check_ty { + check.ty(); + } + } } impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> { @@ -1592,16 +1610,8 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> self.check(item.id, item_visibility).generics().predicates(); 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 && - !trait_item_ref.defaultness.has_value() { - // No type to visit. - } else { - check.ty(); - } + self.check_trait_or_impl_item(trait_item_ref.id.node_id, trait_item_ref.kind, + trait_item_ref.defaultness, item_visibility); } } hir::ItemKind::TraitAlias(..) => { @@ -1647,9 +1657,8 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> } else { impl_vis }; - let mut check = self.check(impl_item.id, impl_item_vis); - check.in_assoc_ty = impl_item_ref.kind == hir::AssociatedItemKind::Type; - check.generics().predicates().ty(); + self.check_trait_or_impl_item(impl_item_ref.id.node_id, impl_item_ref.kind, + impl_item_ref.defaultness, impl_item_vis); } } } diff --git a/src/test/ui/privacy/private-in-public-assoc-ty.rs b/src/test/ui/privacy/private-in-public-assoc-ty.rs index c6e86ed64ae73..81d23959fd4ad 100644 --- a/src/test/ui/privacy/private-in-public-assoc-ty.rs +++ b/src/test/ui/privacy/private-in-public-assoc-ty.rs @@ -1,7 +1,7 @@ // 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)] +#![feature(associated_type_defaults, existential_type)] mod m { struct Priv; @@ -23,10 +23,17 @@ mod m { type Alias4 = Priv; //~^ ERROR private type `m::Priv` in public interface + + type Exist; + fn infer_exist() -> Self::Exist; } impl PubTr for u8 { type Alias1 = Priv; //~^ ERROR private type `m::Priv` in public interface + + existential type Exist: PrivTr; + //~^ ERROR private trait `m::PrivTr` in public interface + fn infer_exist() -> Self::Exist { Priv } } } diff --git a/src/test/ui/privacy/private-in-public-assoc-ty.stderr b/src/test/ui/privacy/private-in-public-assoc-ty.stderr index 6740277c9a7c1..0e5dab1a08c37 100644 --- a/src/test/ui/privacy/private-in-public-assoc-ty.stderr +++ b/src/test/ui/privacy/private-in-public-assoc-ty.stderr @@ -6,7 +6,7 @@ LL | | //~^ WARN private trait `m::PrivTr` in public interface LL | | //~| WARN this was previously accepted LL | | //~| WARN private type `m::Priv` in public interface ... | -LL | | //~^ ERROR private type `m::Priv` in public interface +LL | | fn infer_exist() -> Self::Exist; LL | | } | |_____^ | @@ -22,7 +22,7 @@ LL | | //~^ WARN private trait `m::PrivTr` in public interface LL | | //~| WARN this was previously accepted LL | | //~| WARN private type `m::Priv` in public interface ... | -LL | | //~^ ERROR private type `m::Priv` in public interface +LL | | fn infer_exist() -> Self::Exist; LL | | } | |_____^ | @@ -39,7 +39,7 @@ LL | type Alias4 = Priv; | ^^^^^^^^^^^^^^^^^^^ can't leak private type error[E0446]: private type `m::Priv` in public interface - --> $DIR/private-in-public-assoc-ty.rs:28:9 + --> $DIR/private-in-public-assoc-ty.rs:31:9 | LL | struct Priv; | - `m::Priv` declared as private @@ -47,6 +47,16 @@ LL | struct Priv; LL | type Alias1 = Priv; | ^^^^^^^^^^^^^^^^^^^ can't leak private type -error: aborting due to 2 previous errors +error[E0445]: private trait `m::PrivTr` in public interface + --> $DIR/private-in-public-assoc-ty.rs:34:9 + | +LL | trait PrivTr {} + | - `m::PrivTr` declared as private +... +LL | existential type Exist: PrivTr; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait + +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0446`. +Some errors occurred: E0445, E0446. +For more information about an error, try `rustc --explain E0445`. diff --git a/src/test/ui/privacy/private-in-public-existential.rs b/src/test/ui/privacy/private-in-public-existential.rs index 95658f45df6f5..61c6130e47019 100644 --- a/src/test/ui/privacy/private-in-public-existential.rs +++ b/src/test/ui/privacy/private-in-public-existential.rs @@ -12,4 +12,14 @@ fn check() -> Pub { Priv } +pub trait Trait { + type Pub: Default; + fn method() -> Self::Pub; +} + +impl Trait for u8 { + existential type Pub: Default; + fn method() -> Self::Pub { Priv } +} + fn main() {}