Auto merge of #29973 - petrochenkov:privinpub, r=nikomatsakis
Some notes: This patch enforces the rules from [RFC 136](https://github.com/rust-lang/rfcs/blob/master/text/0136-no-privates-in-public.md) and makes "private in public" a module-level concept and not crate-level. Only `pub` annotations are used by the new algorithm, crate-level exported node set produced by `EmbargoVisitor` is not used. The error messages are tweaked accordingly and don't use the word "exported" to avoid confusing people (https://github.com/rust-lang/rust/issues/29668). The old algorithm tried to be extra smart with impls, but it mostly led to unpredictable behavior and bugs like https://github.com/rust-lang/rust/issues/28325. The new algorithm tries to be as simple as possible - an impl is considered public iff its type is public and its trait is public (if presents). A type or trait is considered public if all its components are public, [complications](https://internals.rust-lang.org/t/limits-of-type-inference-smartness/2919) with private types leaking to other crates/modules through trait impls and type inference are deliberately ignored so far. The new algorithm is not recursive and uses the nice new facility `Crate::visit_all_items`! Obsolete pre-1.0 feature `visible_private_types` is removed. This is a [breaking-change]. The two main vectors of breakage are type aliases (https://github.com/rust-lang/rust/issues/28450) and impls (https://github.com/rust-lang/rust/issues/28325). I need some statistics from a crater run (cc @alexcrichton) to decide on the breakage mitigation strategy. UPDATE: All the new errors are reported as warnings controlled by a lint `private_in_public` and lint group `future_incompatible`, but the intent is to make them hard errors eventually. Closes https://github.com/rust-lang/rust/issues/28325 Closes https://github.com/rust-lang/rust/issues/28450 Closes https://github.com/rust-lang/rust/issues/29524 Closes https://github.com/rust-lang/rust/issues/29627 Closes https://github.com/rust-lang/rust/issues/29668 Closes https://github.com/rust-lang/rust/issues/30055 r? @nikomatsakis
This commit is contained in:
commit
ef91cdb140
@ -2372,10 +2372,6 @@ The currently implemented features of the reference compiler are:
|
||||
Such items should not be allowed by the compiler to exist,
|
||||
so if you need this there probably is a compiler bug.
|
||||
|
||||
* `visible_private_types` - Allows public APIs to expose otherwise private
|
||||
types, e.g. as the return type of a public function.
|
||||
This capability may be removed in the future.
|
||||
|
||||
* `allow_internal_unstable` - Allows `macro_rules!` macros to be tagged with the
|
||||
`#[allow_internal_unstable]` attribute, designed
|
||||
to allow `std` macros to call
|
||||
|
@ -78,7 +78,7 @@ pub struct Node<K, V> {
|
||||
_capacity: usize,
|
||||
}
|
||||
|
||||
struct NodeSlice<'a, K: 'a, V: 'a> {
|
||||
pub struct NodeSlice<'a, K: 'a, V: 'a> {
|
||||
keys: &'a [K],
|
||||
vals: &'a [V],
|
||||
pub edges: &'a [Node<K, V>],
|
||||
@ -87,7 +87,7 @@ struct NodeSlice<'a, K: 'a, V: 'a> {
|
||||
has_edges: bool,
|
||||
}
|
||||
|
||||
struct MutNodeSlice<'a, K: 'a, V: 'a> {
|
||||
pub struct MutNodeSlice<'a, K: 'a, V: 'a> {
|
||||
keys: &'a [K],
|
||||
vals: &'a mut [V],
|
||||
pub edges: &'a mut [Node<K, V>],
|
||||
@ -1344,7 +1344,7 @@ fn min_load_from_capacity(cap: usize) -> usize {
|
||||
/// A trait for pairs of `Iterator`s, one over edges and the other over key/value pairs. This is
|
||||
/// necessary, as the `MoveTraversalImpl` needs to have a destructor that deallocates the `Node`,
|
||||
/// and a pair of `Iterator`s would require two independent destructors.
|
||||
trait TraversalImpl {
|
||||
pub trait TraversalImpl {
|
||||
type Item;
|
||||
type Edge;
|
||||
|
||||
@ -1358,7 +1358,7 @@ trait TraversalImpl {
|
||||
/// A `TraversalImpl` that actually is backed by two iterators. This works in the non-moving case,
|
||||
/// as no deallocation needs to be done.
|
||||
#[derive(Clone)]
|
||||
struct ElemsAndEdges<Elems, Edges>(Elems, Edges);
|
||||
pub struct ElemsAndEdges<Elems, Edges>(Elems, Edges);
|
||||
|
||||
impl<K, V, E, Elems: DoubleEndedIterator, Edges: DoubleEndedIterator>
|
||||
TraversalImpl for ElemsAndEdges<Elems, Edges>
|
||||
@ -1375,7 +1375,7 @@ impl<K, V, E, Elems: DoubleEndedIterator, Edges: DoubleEndedIterator>
|
||||
}
|
||||
|
||||
/// A `TraversalImpl` taking a `Node` by value.
|
||||
struct MoveTraversalImpl<K, V> {
|
||||
pub struct MoveTraversalImpl<K, V> {
|
||||
keys: RawItems<K>,
|
||||
vals: RawItems<V>,
|
||||
edges: RawItems<Node<K, V>>,
|
||||
@ -1436,7 +1436,7 @@ impl<K, V> Drop for MoveTraversalImpl<K, V> {
|
||||
|
||||
/// An abstraction over all the different kinds of traversals a node supports
|
||||
#[derive(Clone)]
|
||||
struct AbsTraversal<Impl> {
|
||||
pub struct AbsTraversal<Impl> {
|
||||
inner: Impl,
|
||||
head_is_edge: bool,
|
||||
tail_is_edge: bool,
|
||||
|
@ -117,6 +117,13 @@ declare_lint! {
|
||||
Allow,
|
||||
"detects trivial casts of numeric types which could be removed"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
pub PRIVATE_IN_PUBLIC,
|
||||
Warn,
|
||||
"detect private items in public interfaces not caught by the old implementation"
|
||||
}
|
||||
|
||||
/// Does nothing as a lint pass, but registers some `Lint`s
|
||||
/// which are used by other parts of the compiler.
|
||||
#[derive(Copy, Clone)]
|
||||
@ -141,6 +148,7 @@ impl LintPass for HardwiredLints {
|
||||
FAT_PTR_TRANSMUTES,
|
||||
TRIVIAL_CASTS,
|
||||
TRIVIAL_NUMERIC_CASTS,
|
||||
PRIVATE_IN_PUBLIC,
|
||||
CONST_ERR
|
||||
)
|
||||
}
|
||||
|
@ -146,6 +146,9 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
|
||||
UNUSED_MUT, UNREACHABLE_CODE, UNUSED_MUST_USE,
|
||||
UNUSED_UNSAFE, PATH_STATEMENTS, UNUSED_ATTRIBUTES);
|
||||
|
||||
add_lint_group!(sess, "future_incompatible",
|
||||
PRIVATE_IN_PUBLIC);
|
||||
|
||||
// We have one lint pass defined specially
|
||||
store.register_late_pass(sess, false, box lint::GatherNodeLevels);
|
||||
|
||||
|
@ -209,7 +209,7 @@ struct ArmBlocks {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct Candidate<'pat, 'tcx:'pat> {
|
||||
pub struct Candidate<'pat, 'tcx:'pat> {
|
||||
// all of these must be satisfied...
|
||||
match_pairs: Vec<MatchPair<'pat, 'tcx>>,
|
||||
|
||||
@ -235,7 +235,7 @@ struct Binding<'tcx> {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct MatchPair<'pat, 'tcx:'pat> {
|
||||
pub struct MatchPair<'pat, 'tcx:'pat> {
|
||||
// this lvalue...
|
||||
lvalue: Lvalue<'tcx>,
|
||||
|
||||
@ -278,7 +278,7 @@ enum TestKind<'tcx> {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Test<'tcx> {
|
||||
pub struct Test<'tcx> {
|
||||
span: Span,
|
||||
kind: TestKind<'tcx>,
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ use rustc_front::hir;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
|
||||
struct Builder<'a, 'tcx: 'a> {
|
||||
pub struct Builder<'a, 'tcx: 'a> {
|
||||
hir: Cx<'a, 'tcx>,
|
||||
cfg: CFG<'tcx>,
|
||||
scopes: Vec<scope::Scope<'tcx>>,
|
||||
@ -40,7 +40,7 @@ struct CFG<'tcx> {
|
||||
// convenient.
|
||||
|
||||
#[must_use] // if you don't use one of these results, you're leaving a dangling edge
|
||||
struct BlockAnd<T>(BasicBlock, T);
|
||||
pub struct BlockAnd<T>(BasicBlock, T);
|
||||
|
||||
trait BlockAndExtension {
|
||||
fn and<T>(self, v: T) -> BlockAnd<T>;
|
||||
|
@ -21,13 +21,14 @@ trait Foo {
|
||||
fn dummy(&self) { }
|
||||
}
|
||||
|
||||
pub trait Bar : Foo {} // error: private trait in exported type parameter bound
|
||||
pub trait Bar : Foo {} // error: private trait in public interface
|
||||
pub struct Bar<T: Foo>(pub T); // same error
|
||||
pub fn foo<T: Foo> (t: T) {} // same error
|
||||
```
|
||||
|
||||
To solve this error, please ensure that the trait is also public and accessible
|
||||
at the same level of the public functions or types which are bound on it.
|
||||
To solve this error, please ensure that the trait is also public. The trait
|
||||
can be made inaccessible if necessary by placing it into a private inner module,
|
||||
but it still has to be marked with `pub`.
|
||||
Example:
|
||||
|
||||
```
|
||||
@ -42,20 +43,22 @@ pub fn foo<T: Foo> (t: T) {} // ok!
|
||||
"##,
|
||||
|
||||
E0446: r##"
|
||||
A private type was used in an exported type signature. Erroneous code example:
|
||||
A private type was used in a public type signature. Erroneous code example:
|
||||
|
||||
```
|
||||
mod Foo {
|
||||
struct Bar(u32);
|
||||
|
||||
pub fn bar() -> Bar { // error: private type in exported type signature
|
||||
pub fn bar() -> Bar { // error: private type in public interface
|
||||
Bar(0)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
To solve this error, please ensure that the type is also public and accessible
|
||||
at the same level of the public functions or types which use it. Example:
|
||||
To solve this error, please ensure that the type is also public. The type
|
||||
can be made inaccessible if necessary by placing it into a private inner module,
|
||||
but it still has to be marked with `pub`.
|
||||
Example:
|
||||
|
||||
```
|
||||
mod Foo {
|
||||
|
@ -38,6 +38,7 @@ use std::mem::replace;
|
||||
use rustc_front::hir;
|
||||
use rustc_front::intravisit::{self, Visitor};
|
||||
|
||||
use rustc::lint;
|
||||
use rustc::middle::def;
|
||||
use rustc::middle::def_id::DefId;
|
||||
use rustc::middle::privacy::{AccessLevel, AccessLevels};
|
||||
@ -46,7 +47,7 @@ use rustc::middle::privacy::LastPrivate::*;
|
||||
use rustc::middle::privacy::PrivateDep::*;
|
||||
use rustc::middle::privacy::ExternalExports;
|
||||
use rustc::middle::ty;
|
||||
use rustc::util::nodemap::NodeMap;
|
||||
use rustc::util::nodemap::{NodeMap, NodeSet};
|
||||
use rustc::front::map as ast_map;
|
||||
|
||||
use syntax::ast;
|
||||
@ -1101,14 +1102,23 @@ impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
struct VisiblePrivateTypesVisitor<'a, 'tcx: 'a> {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// Obsolete visitors for checking for private items in public interfaces.
|
||||
/// These visitors are supposed to be kept in frozen state and produce an
|
||||
/// "old error node set". For backward compatibility the new visitor reports
|
||||
/// warnings instead of hard errors when the erroneous node is not in this old set.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx: 'a> {
|
||||
tcx: &'a ty::ctxt<'tcx>,
|
||||
access_levels: &'a AccessLevels,
|
||||
in_variant: bool,
|
||||
// set of errors produced by this obsolete visitor
|
||||
old_error_set: NodeSet,
|
||||
}
|
||||
|
||||
struct CheckTypeForPrivatenessVisitor<'a, 'b: 'a, 'tcx: 'b> {
|
||||
inner: &'a VisiblePrivateTypesVisitor<'b, 'tcx>,
|
||||
struct ObsoleteCheckTypeForPrivatenessVisitor<'a, 'b: 'a, 'tcx: 'b> {
|
||||
inner: &'a ObsoleteVisiblePrivateTypesVisitor<'b, 'tcx>,
|
||||
/// whether the type refers to private types.
|
||||
contains_private: bool,
|
||||
/// whether we've recurred at all (i.e. if we're pointing at the
|
||||
@ -1118,7 +1128,7 @@ struct CheckTypeForPrivatenessVisitor<'a, 'b: 'a, 'tcx: 'b> {
|
||||
outer_type_is_public_path: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> VisiblePrivateTypesVisitor<'a, 'tcx> {
|
||||
impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
|
||||
fn path_is_private_type(&self, path_id: ast::NodeId) -> bool {
|
||||
let did = match self.tcx.def_map.borrow().get(&path_id).map(|d| d.full_def()) {
|
||||
// `int` etc. (None doesn't seem to occur.)
|
||||
@ -1146,14 +1156,11 @@ impl<'a, 'tcx> VisiblePrivateTypesVisitor<'a, 'tcx> {
|
||||
self.access_levels.is_public(trait_id)
|
||||
}
|
||||
|
||||
fn check_ty_param_bound(&self,
|
||||
fn check_ty_param_bound(&mut self,
|
||||
ty_param_bound: &hir::TyParamBound) {
|
||||
if let hir::TraitTyParamBound(ref trait_ref, _) = *ty_param_bound {
|
||||
if !self.tcx.sess.features.borrow().visible_private_types &&
|
||||
self.path_is_private_type(trait_ref.trait_ref.ref_id) {
|
||||
let span = trait_ref.trait_ref.path.span;
|
||||
span_err!(self.tcx.sess, span, E0445,
|
||||
"private trait in exported type parameter bound");
|
||||
if self.path_is_private_type(trait_ref.trait_ref.ref_id) {
|
||||
self.old_error_set.insert(trait_ref.trait_ref.ref_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1163,7 +1170,7 @@ impl<'a, 'tcx> VisiblePrivateTypesVisitor<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'tcx, 'v> Visitor<'v> for CheckTypeForPrivatenessVisitor<'a, 'b, 'tcx> {
|
||||
impl<'a, 'b, 'tcx, 'v> Visitor<'v> for ObsoleteCheckTypeForPrivatenessVisitor<'a, 'b, 'tcx> {
|
||||
fn visit_ty(&mut self, ty: &hir::Ty) {
|
||||
if let hir::TyPath(..) = ty.node {
|
||||
if self.inner.path_is_private_type(ty.id) {
|
||||
@ -1183,7 +1190,7 @@ impl<'a, 'b, 'tcx, 'v> Visitor<'v> for CheckTypeForPrivatenessVisitor<'a, 'b, 't
|
||||
fn visit_expr(&mut self, _: &hir::Expr) {}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> {
|
||||
impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
|
||||
/// We want to visit items in the context of their containing
|
||||
/// module and so forth, so supply a crate for doing a deep walk.
|
||||
fn visit_nested_item(&mut self, item: hir::ItemId) {
|
||||
@ -1224,7 +1231,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> {
|
||||
|
||||
// check the properties of the Self type:
|
||||
{
|
||||
let mut visitor = CheckTypeForPrivatenessVisitor {
|
||||
let mut visitor = ObsoleteCheckTypeForPrivatenessVisitor {
|
||||
inner: self,
|
||||
contains_private: false,
|
||||
at_outer_type: true,
|
||||
@ -1401,11 +1408,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> {
|
||||
|
||||
fn visit_ty(&mut self, t: &hir::Ty) {
|
||||
debug!("VisiblePrivateTypesVisitor checking ty {:?}", t);
|
||||
if let hir::TyPath(_, ref p) = t.node {
|
||||
if !self.tcx.sess.features.borrow().visible_private_types &&
|
||||
self.path_is_private_type(t.id) {
|
||||
span_err!(self.tcx.sess, p.span, E0446,
|
||||
"private type in exported type signature");
|
||||
if let hir::TyPath(..) = t.node {
|
||||
if self.path_is_private_type(t.id) {
|
||||
self.old_error_set.insert(t.id);
|
||||
}
|
||||
}
|
||||
intravisit::walk_ty(self, t)
|
||||
@ -1439,6 +1444,235 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> {
|
||||
fn visit_expr(&mut self, _: &hir::Expr) {}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// SearchInterfaceForPrivateItemsVisitor traverses an item's interface and
|
||||
/// finds any private components in it.
|
||||
/// PrivateItemsInPublicInterfacesVisitor ensures there are no private types
|
||||
/// and traits in public interfaces.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct SearchInterfaceForPrivateItemsVisitor<'a, 'tcx: 'a> {
|
||||
tcx: &'a ty::ctxt<'tcx>,
|
||||
// Do not report an error when a private type is found
|
||||
is_quiet: bool,
|
||||
// Is private component found?
|
||||
is_public: bool,
|
||||
old_error_set: &'a NodeSet,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
|
||||
// Check if the type alias contain private types when substituted
|
||||
fn is_public_type_alias(&self, item: &hir::Item, path: &hir::Path) -> bool {
|
||||
// We substitute type aliases only when determining impl publicity
|
||||
// FIXME: This will probably change and all type aliases will be substituted,
|
||||
// requires an amendment to RFC 136.
|
||||
if !self.is_quiet {
|
||||
return false
|
||||
}
|
||||
// Type alias is considered public if the aliased type is
|
||||
// public, even if the type alias itself is private. So, something
|
||||
// like `type A = u8; pub fn f() -> A {...}` doesn't cause an error.
|
||||
if let hir::ItemTy(ref ty, ref generics) = item.node {
|
||||
let mut check = SearchInterfaceForPrivateItemsVisitor { is_public: true, ..*self };
|
||||
check.visit_ty(ty);
|
||||
// If a private type alias with default type parameters is used in public
|
||||
// interface we must ensure, that the defaults are public if they are actually used.
|
||||
// ```
|
||||
// type Alias<T = Private> = T;
|
||||
// pub fn f() -> Alias {...} // `Private` is implicitly used here, so it must be public
|
||||
// ```
|
||||
let provided_params = path.segments.last().unwrap().parameters.types().len();
|
||||
for ty_param in &generics.ty_params[provided_params..] {
|
||||
if let Some(ref default_ty) = ty_param.default {
|
||||
check.visit_ty(default_ty);
|
||||
}
|
||||
}
|
||||
check.is_public
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx: 'a, 'v> Visitor<'v> for SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
|
||||
fn visit_ty(&mut self, ty: &hir::Ty) {
|
||||
if self.is_quiet && !self.is_public {
|
||||
// We are in quiet mode and a private type is already found, no need to proceed
|
||||
return
|
||||
}
|
||||
if let hir::TyPath(_, ref path) = ty.node {
|
||||
let def = self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def();
|
||||
match def {
|
||||
def::DefPrimTy(..) | def::DefSelfTy(..) | def::DefTyParam(..) => {
|
||||
// Public
|
||||
}
|
||||
def::DefAssociatedTy(..) if self.is_quiet => {
|
||||
// Conservatively approximate the whole type alias as public without
|
||||
// recursing into its components when determining impl publicity.
|
||||
// For example, `impl <Type as Trait>::Alias {...}` may be a public impl
|
||||
// even if both `Type` and `Trait` are private.
|
||||
// Ideally, associated types should be substituted in the same way as
|
||||
// free type aliases, but this isn't done yet.
|
||||
return
|
||||
}
|
||||
def::DefStruct(def_id) | def::DefTy(def_id, _) |
|
||||
def::DefTrait(def_id) | def::DefAssociatedTy(def_id, _) => {
|
||||
// Non-local means public (private items can't leave their crate, modulo bugs)
|
||||
if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
|
||||
let item = self.tcx.map.expect_item(node_id);
|
||||
if item.vis != hir::Public && !self.is_public_type_alias(item, path) {
|
||||
if !self.is_quiet {
|
||||
if self.old_error_set.contains(&ty.id) {
|
||||
span_err!(self.tcx.sess, ty.span, E0446,
|
||||
"private type in public interface");
|
||||
} else {
|
||||
self.tcx.sess.add_lint (
|
||||
lint::builtin::PRIVATE_IN_PUBLIC,
|
||||
node_id,
|
||||
ty.span,
|
||||
"private type in public interface (error E0446)".to_string()
|
||||
);
|
||||
}
|
||||
}
|
||||
self.is_public = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
intravisit::walk_ty(self, ty);
|
||||
}
|
||||
|
||||
fn visit_trait_ref(&mut self, trait_ref: &hir::TraitRef) {
|
||||
if self.is_quiet && !self.is_public {
|
||||
// We are in quiet mode and a private type is already found, no need to proceed
|
||||
return
|
||||
}
|
||||
// Non-local means public (private items can't leave their crate, modulo bugs)
|
||||
let def_id = self.tcx.trait_ref_to_def_id(trait_ref);
|
||||
if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
|
||||
let item = self.tcx.map.expect_item(node_id);
|
||||
if item.vis != hir::Public {
|
||||
if !self.is_quiet {
|
||||
if self.old_error_set.contains(&trait_ref.ref_id) {
|
||||
span_err!(self.tcx.sess, trait_ref.path.span, E0445,
|
||||
"private trait in public interface");
|
||||
} else {
|
||||
self.tcx.sess.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
|
||||
node_id,
|
||||
trait_ref.path.span,
|
||||
"private trait in public interface (error E0445)"
|
||||
.to_string());
|
||||
}
|
||||
}
|
||||
self.is_public = false;
|
||||
}
|
||||
}
|
||||
|
||||
intravisit::walk_trait_ref(self, trait_ref);
|
||||
}
|
||||
|
||||
// Don't recurse into function bodies
|
||||
fn visit_block(&mut self, _: &hir::Block) {}
|
||||
// Don't recurse into expressions in array sizes or const initializers
|
||||
fn visit_expr(&mut self, _: &hir::Expr) {}
|
||||
// Don't recurse into patterns in function arguments
|
||||
fn visit_pat(&mut self, _: &hir::Pat) {}
|
||||
}
|
||||
|
||||
struct PrivateItemsInPublicInterfacesVisitor<'a, 'tcx: 'a> {
|
||||
tcx: &'a ty::ctxt<'tcx>,
|
||||
old_error_set: &'a NodeSet,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
|
||||
// A type is considered public if it doesn't contain any private components
|
||||
fn is_public_ty(&self, ty: &hir::Ty) -> bool {
|
||||
let mut check = SearchInterfaceForPrivateItemsVisitor {
|
||||
tcx: self.tcx, is_quiet: true, is_public: true, old_error_set: self.old_error_set
|
||||
};
|
||||
check.visit_ty(ty);
|
||||
check.is_public
|
||||
}
|
||||
|
||||
// A trait reference is considered public if it doesn't contain any private components
|
||||
fn is_public_trait_ref(&self, trait_ref: &hir::TraitRef) -> bool {
|
||||
let mut check = SearchInterfaceForPrivateItemsVisitor {
|
||||
tcx: self.tcx, is_quiet: true, is_public: true, old_error_set: self.old_error_set
|
||||
};
|
||||
check.visit_trait_ref(trait_ref);
|
||||
check.is_public
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx, 'v> Visitor<'v> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
|
||||
fn visit_item(&mut self, item: &hir::Item) {
|
||||
let mut check = SearchInterfaceForPrivateItemsVisitor {
|
||||
tcx: self.tcx, is_quiet: false, is_public: true, old_error_set: self.old_error_set
|
||||
};
|
||||
match item.node {
|
||||
// Crates are always public
|
||||
hir::ItemExternCrate(..) => {}
|
||||
// All nested items are checked by visit_item
|
||||
hir::ItemMod(..) => {}
|
||||
// Checked in resolve
|
||||
hir::ItemUse(..) => {}
|
||||
// Subitems of these items have inherited publicity
|
||||
hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) |
|
||||
hir::ItemEnum(..) | hir::ItemTrait(..) | hir::ItemTy(..) => {
|
||||
if item.vis == hir::Public {
|
||||
check.visit_item(item);
|
||||
}
|
||||
}
|
||||
// Subitems of foreign modules have their own publicity
|
||||
hir::ItemForeignMod(ref foreign_mod) => {
|
||||
for foreign_item in &foreign_mod.items {
|
||||
if foreign_item.vis == hir::Public {
|
||||
check.visit_foreign_item(foreign_item);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Subitems of structs have their own publicity
|
||||
hir::ItemStruct(ref struct_def, ref generics) => {
|
||||
if item.vis == hir::Public {
|
||||
check.visit_generics(generics);
|
||||
for field in struct_def.fields() {
|
||||
if field.node.kind.visibility() == hir::Public {
|
||||
check.visit_struct_field(field);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// The interface is empty
|
||||
hir::ItemDefaultImpl(..) => {}
|
||||
// An inherent impl is public when its type is public
|
||||
// Subitems of inherent impls have their own publicity
|
||||
hir::ItemImpl(_, _, ref generics, None, ref ty, ref impl_items) => {
|
||||
if self.is_public_ty(ty) {
|
||||
check.visit_generics(generics);
|
||||
for impl_item in impl_items {
|
||||
if impl_item.vis == hir::Public {
|
||||
check.visit_impl_item(impl_item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// A trait impl is public when both its type and its trait are public
|
||||
// Subitems of trait impls have inherited publicity
|
||||
hir::ItemImpl(_, _, ref generics, Some(ref trait_ref), ref ty, ref impl_items) => {
|
||||
if self.is_public_ty(ty) && self.is_public_trait_ref(trait_ref) {
|
||||
check.visit_generics(generics);
|
||||
for impl_item in impl_items {
|
||||
check.visit_impl_item(impl_item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_crate(tcx: &ty::ctxt,
|
||||
export_map: &def::ExportMap,
|
||||
external_exports: ExternalExports)
|
||||
@ -1492,18 +1726,24 @@ pub fn check_crate(tcx: &ty::ctxt,
|
||||
}
|
||||
visitor.update(ast::CRATE_NODE_ID, Some(AccessLevel::Public));
|
||||
|
||||
let EmbargoVisitor { access_levels, .. } = visitor;
|
||||
|
||||
{
|
||||
let mut visitor = VisiblePrivateTypesVisitor {
|
||||
let mut visitor = ObsoleteVisiblePrivateTypesVisitor {
|
||||
tcx: tcx,
|
||||
access_levels: &access_levels,
|
||||
access_levels: &visitor.access_levels,
|
||||
in_variant: false,
|
||||
old_error_set: NodeSet(),
|
||||
};
|
||||
intravisit::walk_crate(&mut visitor, krate);
|
||||
|
||||
// Check for private types and traits in public interfaces
|
||||
let mut visitor = PrivateItemsInPublicInterfacesVisitor {
|
||||
tcx: tcx,
|
||||
old_error_set: &visitor.old_error_set,
|
||||
};
|
||||
krate.visit_all_items(&mut visitor);
|
||||
}
|
||||
|
||||
access_levels
|
||||
visitor.access_levels
|
||||
}
|
||||
|
||||
__build_diagnostic_array! { librustc_privacy, DIAGNOSTICS }
|
||||
|
@ -390,9 +390,15 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
|
||||
let module = Module::new(parent_link, Some(def), false, is_public);
|
||||
name_bindings.define_module(module.clone(), sp);
|
||||
|
||||
let variant_modifiers = if is_public {
|
||||
DefModifiers::empty()
|
||||
} else {
|
||||
DefModifiers::PRIVATE_VARIANT
|
||||
};
|
||||
for variant in &(*enum_definition).variants {
|
||||
let item_def_id = self.ast_map.local_def_id(item.id);
|
||||
self.build_reduced_graph_for_variant(variant, item_def_id, &module);
|
||||
self.build_reduced_graph_for_variant(variant, item_def_id,
|
||||
&module, variant_modifiers);
|
||||
}
|
||||
parent.clone()
|
||||
}
|
||||
@ -494,7 +500,8 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
|
||||
fn build_reduced_graph_for_variant(&mut self,
|
||||
variant: &Variant,
|
||||
item_id: DefId,
|
||||
parent: &Rc<Module>) {
|
||||
parent: &Rc<Module>,
|
||||
variant_modifiers: DefModifiers) {
|
||||
let name = variant.node.name;
|
||||
let is_exported = if variant.node.data.is_struct() {
|
||||
// Not adding fields for variants as they are not accessed with a self receiver
|
||||
@ -512,12 +519,12 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
|
||||
self.ast_map.local_def_id(variant.node.data.id()),
|
||||
is_exported),
|
||||
variant.span,
|
||||
DefModifiers::PUBLIC | DefModifiers::IMPORTABLE);
|
||||
DefModifiers::PUBLIC | DefModifiers::IMPORTABLE | variant_modifiers);
|
||||
child.define_type(DefVariant(item_id,
|
||||
self.ast_map.local_def_id(variant.node.data.id()),
|
||||
is_exported),
|
||||
variant.span,
|
||||
DefModifiers::PUBLIC | DefModifiers::IMPORTABLE);
|
||||
DefModifiers::PUBLIC | DefModifiers::IMPORTABLE | variant_modifiers);
|
||||
}
|
||||
|
||||
/// Constructs the reduced graph for one foreign item.
|
||||
|
@ -905,8 +905,13 @@ impl fmt::Debug for Module {
|
||||
bitflags! {
|
||||
#[derive(Debug)]
|
||||
flags DefModifiers: u8 {
|
||||
// Enum variants are always considered `PUBLIC`, this is needed for `use Enum::Variant`
|
||||
// or `use Enum::*` to work on private enums.
|
||||
const PUBLIC = 1 << 0,
|
||||
const IMPORTABLE = 1 << 1,
|
||||
// Variants are considered `PUBLIC`, but some of them live in private enums.
|
||||
// We need to track them to prohibit reexports like `pub use PrivEnum::Variant`.
|
||||
const PRIVATE_VARIANT = 1 << 2,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@ use {resolve_error, ResolutionError};
|
||||
|
||||
use build_reduced_graph;
|
||||
|
||||
use rustc::lint;
|
||||
use rustc::middle::def::*;
|
||||
use rustc::middle::def_id::DefId;
|
||||
use rustc::middle::privacy::*;
|
||||
@ -452,6 +453,17 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
||||
self.resolver.session.span_note(directive.span, ¬e_msg);
|
||||
pub_err = true;
|
||||
}
|
||||
if directive.is_public && child_name_bindings.value_ns.
|
||||
defined_with(DefModifiers::PRIVATE_VARIANT) {
|
||||
let msg = format!("variant `{}` is private, and cannot be reexported ( \
|
||||
error E0364), consider declaring its enum as `pub`",
|
||||
source);
|
||||
self.resolver.session.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
|
||||
directive.id,
|
||||
directive.span,
|
||||
msg);
|
||||
pub_err = true;
|
||||
}
|
||||
}
|
||||
if child_name_bindings.type_ns.defined() {
|
||||
debug!("(resolving single import) found type binding");
|
||||
@ -465,6 +477,16 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
||||
span_err!(self.resolver.session, directive.span, E0365, "{}", &msg);
|
||||
self.resolver.session.span_note(directive.span, ¬e_msg);
|
||||
}
|
||||
if !pub_err && directive.is_public && child_name_bindings.type_ns.
|
||||
defined_with(DefModifiers::PRIVATE_VARIANT) {
|
||||
let msg = format!("variant `{}` is private, and cannot be reexported ( \
|
||||
error E0365), consider declaring its enum as `pub`",
|
||||
source);
|
||||
self.resolver.session.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
|
||||
directive.id,
|
||||
directive.span,
|
||||
msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -842,10 +864,22 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
||||
module_to_string(module_));
|
||||
|
||||
// Merge the child item into the import resolution.
|
||||
// pub_err makes sure we don't give the same error twice.
|
||||
let mut pub_err = false;
|
||||
{
|
||||
let mut merge_child_item = |namespace| {
|
||||
let modifier = DefModifiers::IMPORTABLE | DefModifiers::PUBLIC;
|
||||
if !pub_err && is_public &&
|
||||
name_bindings[namespace].defined_with(DefModifiers::PRIVATE_VARIANT) {
|
||||
let msg = format!("variant `{}` is private, and cannot be reexported (error \
|
||||
E0364), consider declaring its enum as `pub`", name);
|
||||
self.resolver.session.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
|
||||
import_directive.id,
|
||||
import_directive.span,
|
||||
msg);
|
||||
pub_err = true;
|
||||
}
|
||||
|
||||
let modifier = DefModifiers::IMPORTABLE | DefModifiers::PUBLIC;
|
||||
if name_bindings[namespace].defined_with(modifier) {
|
||||
let namespace_name = match namespace {
|
||||
TypeNS => "type",
|
||||
|
@ -14,7 +14,7 @@ use std::os::windows::prelude::*;
|
||||
use std::ptr;
|
||||
use libc::{c_void, c_long};
|
||||
|
||||
type DWORD = u32;
|
||||
pub type DWORD = u32;
|
||||
type LPCWSTR = *const u16;
|
||||
type LONG = c_long;
|
||||
type LPDWORD = *mut DWORD;
|
||||
@ -34,7 +34,7 @@ const SYNCHRONIZE: REGSAM = 0x00100000;
|
||||
const REG_SZ: DWORD = 1;
|
||||
const ERROR_SUCCESS: i32 = 0;
|
||||
|
||||
enum __HKEY__ {}
|
||||
pub enum __HKEY__ {}
|
||||
pub type HKEY = *mut __HKEY__;
|
||||
pub type PHKEY = *mut HKEY;
|
||||
pub type REGSAM = DWORD;
|
||||
|
@ -145,7 +145,7 @@ impl FunctionDebugContext {
|
||||
}
|
||||
}
|
||||
|
||||
struct FunctionDebugContextData {
|
||||
pub struct FunctionDebugContextData {
|
||||
scope_map: RefCell<NodeMap<DIScope>>,
|
||||
fn_metadata: DISubprogram,
|
||||
argument_counter: Cell<usize>,
|
||||
|
@ -123,7 +123,7 @@ pub enum BucketState<K, V, M> {
|
||||
// A GapThenFull encapsulates the state of two consecutive buckets at once.
|
||||
// The first bucket, called the gap, is known to be empty.
|
||||
// The second bucket is full.
|
||||
struct GapThenFull<K, V, M> {
|
||||
pub struct GapThenFull<K, V, M> {
|
||||
gap: EmptyBucket<K, V, ()>,
|
||||
full: FullBucket<K, V, M>,
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Option<u32>, Status
|
||||
("advanced_slice_patterns", "1.0.0", Some(23121), Active),
|
||||
("tuple_indexing", "1.0.0", None, Accepted),
|
||||
("associated_types", "1.0.0", None, Accepted),
|
||||
("visible_private_types", "1.0.0", Some(29627), Active),
|
||||
("visible_private_types", "1.0.0", None, Removed),
|
||||
("slicing_syntax", "1.0.0", None, Accepted),
|
||||
("box_syntax", "1.0.0", Some(27779), Active),
|
||||
("placement_in_syntax", "1.0.0", Some(27779), Active),
|
||||
@ -514,7 +514,6 @@ pub enum AttributeGate {
|
||||
pub struct Features {
|
||||
pub unboxed_closures: bool,
|
||||
pub rustc_diagnostic_macros: bool,
|
||||
pub visible_private_types: bool,
|
||||
pub allow_quote: bool,
|
||||
pub allow_asm: bool,
|
||||
pub allow_log_syntax: bool,
|
||||
@ -551,7 +550,6 @@ impl Features {
|
||||
Features {
|
||||
unboxed_closures: false,
|
||||
rustc_diagnostic_macros: false,
|
||||
visible_private_types: false,
|
||||
allow_quote: false,
|
||||
allow_asm: false,
|
||||
allow_log_syntax: false,
|
||||
@ -1130,7 +1128,6 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &Handler,
|
||||
Features {
|
||||
unboxed_closures: cx.has_feature("unboxed_closures"),
|
||||
rustc_diagnostic_macros: cx.has_feature("rustc_diagnostic_macros"),
|
||||
visible_private_types: cx.has_feature("visible_private_types"),
|
||||
allow_quote: cx.has_feature("quote"),
|
||||
allow_asm: cx.has_feature("asm"),
|
||||
allow_log_syntax: cx.has_feature("log_syntax"),
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
use std::marker;
|
||||
|
||||
struct arc_destruct<T: Sync> {
|
||||
pub struct arc_destruct<T: Sync> {
|
||||
_data: isize,
|
||||
_marker: marker::PhantomData<T>
|
||||
}
|
||||
@ -37,7 +37,7 @@ fn init() -> arc_destruct<context_res> {
|
||||
arc(context_res())
|
||||
}
|
||||
|
||||
struct context_res {
|
||||
pub struct context_res {
|
||||
ctx : isize,
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ use foo::NoResult; // Through a re-export
|
||||
mod foo {
|
||||
pub use self::MyEnum::NoResult;
|
||||
|
||||
enum MyEnum {
|
||||
pub enum MyEnum {
|
||||
Result,
|
||||
NoResult
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ use std::any::TypeId;
|
||||
trait Private<P, R> {
|
||||
fn call(&self, p: P, r: R);
|
||||
}
|
||||
pub trait Public: Private< //~ ERROR private trait in exported type parameter bound
|
||||
pub trait Public: Private< //~ ERROR private trait in public interface
|
||||
<Self as Public>::P,
|
||||
<Self as Public>::R
|
||||
> {
|
||||
|
@ -49,7 +49,7 @@ struct UsedStruct1 {
|
||||
}
|
||||
struct UsedStruct2(isize);
|
||||
struct UsedStruct3;
|
||||
struct UsedStruct4;
|
||||
pub struct UsedStruct4;
|
||||
// this struct is never used directly, but its method is, so we don't want
|
||||
// to warn it
|
||||
struct SemiUsedStruct;
|
||||
|
@ -1,123 +0,0 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
#![allow(dead_code)]
|
||||
#![crate_type="lib"]
|
||||
|
||||
use std::marker;
|
||||
|
||||
struct Private<T>(marker::PhantomData<T>);
|
||||
pub struct Public<T>(marker::PhantomData<T>);
|
||||
|
||||
impl Private<Public<isize>> {
|
||||
pub fn a(&self) -> Private<isize> { panic!() }
|
||||
fn b(&self) -> Private<isize> { panic!() }
|
||||
|
||||
pub fn c() -> Private<isize> { panic!() }
|
||||
fn d() -> Private<isize> { panic!() }
|
||||
}
|
||||
impl Private<isize> {
|
||||
pub fn e(&self) -> Private<isize> { panic!() }
|
||||
fn f(&self) -> Private<isize> { panic!() }
|
||||
}
|
||||
|
||||
impl Public<Private<isize>> {
|
||||
pub fn a(&self) -> Private<isize> { panic!() }
|
||||
fn b(&self) -> Private<isize> { panic!() }
|
||||
|
||||
pub fn c() -> Private<isize> { panic!() } //~ ERROR private type in exported type signature
|
||||
fn d() -> Private<isize> { panic!() }
|
||||
}
|
||||
impl Public<isize> {
|
||||
pub fn e(&self) -> Private<isize> { panic!() } //~ ERROR private type in exported type signature
|
||||
fn f(&self) -> Private<isize> { panic!() }
|
||||
}
|
||||
|
||||
pub fn x(_: Private<isize>) {} //~ ERROR private type in exported type signature
|
||||
|
||||
fn y(_: Private<isize>) {}
|
||||
|
||||
|
||||
pub struct Foo {
|
||||
pub x: Private<isize>, //~ ERROR private type in exported type signature
|
||||
y: Private<isize>
|
||||
}
|
||||
|
||||
struct Bar {
|
||||
x: Private<isize>,
|
||||
}
|
||||
|
||||
pub enum Baz {
|
||||
Baz1(Private<isize>), //~ ERROR private type in exported type signature
|
||||
Baz2 {
|
||||
y: Private<isize> //~ ERROR private type in exported type signature
|
||||
},
|
||||
}
|
||||
|
||||
enum Qux {
|
||||
Qux1(Private<isize>),
|
||||
Qux2 {
|
||||
x: Private<isize>,
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PubTrait {
|
||||
fn foo(&self) -> Private<isize> { panic!( )} //~ ERROR private type in exported type signature
|
||||
fn bar(&self) -> Private<isize>; //~ ERROR private type in exported type signature
|
||||
fn baz() -> Private<isize>; //~ ERROR private type in exported type signature
|
||||
}
|
||||
|
||||
impl PubTrait for Public<isize> {
|
||||
fn bar(&self) -> Private<isize> { panic!() }
|
||||
fn baz() -> Private<isize> { panic!() }
|
||||
}
|
||||
impl PubTrait for Public<Private<isize>> {
|
||||
fn bar(&self) -> Private<isize> { panic!() }
|
||||
fn baz() -> Private<isize> { panic!() }
|
||||
}
|
||||
|
||||
impl PubTrait for Private<isize> {
|
||||
fn bar(&self) -> Private<isize> { panic!() }
|
||||
fn baz() -> Private<isize> { panic!() }
|
||||
}
|
||||
impl PubTrait for (Private<isize>,) {
|
||||
fn bar(&self) -> Private<isize> { panic!() }
|
||||
fn baz() -> Private<isize> { panic!() }
|
||||
}
|
||||
|
||||
|
||||
trait PrivTrait {
|
||||
fn foo(&self) -> Private<isize> { panic!( )}
|
||||
fn bar(&self) -> Private<isize>;
|
||||
}
|
||||
impl PrivTrait for Private<isize> {
|
||||
fn bar(&self) -> Private<isize> { panic!() }
|
||||
}
|
||||
impl PrivTrait for (Private<isize>,) {
|
||||
fn bar(&self) -> Private<isize> { panic!() }
|
||||
}
|
||||
|
||||
pub trait ParamTrait<T> {
|
||||
fn foo() -> T;
|
||||
}
|
||||
|
||||
impl ParamTrait<Private<isize>> //~ ERROR private type in exported type signature
|
||||
for Public<isize> {
|
||||
fn foo() -> Private<isize> { panic!() }
|
||||
}
|
||||
|
||||
impl ParamTrait<Private<isize>> for Private<isize> {
|
||||
fn foo() -> Private<isize> { panic!( )}
|
||||
}
|
||||
|
||||
impl<T: ParamTrait<Private<isize>>> //~ ERROR private type in exported type signature
|
||||
ParamTrait<T> for Public<i8> {
|
||||
fn foo() -> T { panic!() }
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
// Test that we properly check for private types in public signatures, even
|
||||
// inside a private module (#22261).
|
||||
|
||||
mod a {
|
||||
struct Priv;
|
||||
|
||||
pub fn expose_a() -> Priv { //~Error: private type in exported type signature
|
||||
panic!();
|
||||
}
|
||||
|
||||
mod b {
|
||||
pub fn expose_b() -> super::Priv { //~Error: private type in exported type signature
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {}
|
@ -8,16 +8,26 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// pretty-expanded FIXME #23616
|
||||
mod m1 {
|
||||
#![deny(private_in_public)]
|
||||
|
||||
#![feature(visible_private_types)]
|
||||
pub struct Pub;
|
||||
struct Priv;
|
||||
|
||||
trait Foo { fn dummy(&self) { } }
|
||||
impl Pub {
|
||||
pub fn f() -> Priv {} //~ ERROR private type in public interface
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Bar : Foo {}
|
||||
mod m2 {
|
||||
#![deny(future_incompatible)]
|
||||
|
||||
struct Baz;
|
||||
pub struct Pub;
|
||||
struct Priv;
|
||||
|
||||
pub fn f(_: Baz) {}
|
||||
impl Pub {
|
||||
pub fn f() -> Priv {} //~ ERROR private type in public interface
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
251
src/test/compile-fail/private-in-public-warn.rs
Normal file
251
src/test/compile-fail/private-in-public-warn.rs
Normal file
@ -0,0 +1,251 @@
|
||||
// Copyright 2015 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 public interfaces.
|
||||
// This test also ensures that the checks are performed even inside private modules.
|
||||
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(associated_consts)]
|
||||
#![feature(associated_type_defaults)]
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_variables)]
|
||||
#![allow(improper_ctypes)]
|
||||
|
||||
mod types {
|
||||
struct Priv;
|
||||
pub struct Pub;
|
||||
pub trait PubTr {
|
||||
type Alias;
|
||||
}
|
||||
|
||||
pub type Alias = Priv; //~ WARN private type in public interface
|
||||
pub enum E {
|
||||
V1(Priv), //~ WARN private type in public interface
|
||||
V2 { field: Priv }, //~ WARN private type in public interface
|
||||
}
|
||||
pub trait Tr {
|
||||
const C: Priv = Priv; //~ WARN private type in public interface
|
||||
type Alias = Priv; //~ WARN private type in public interface
|
||||
fn f1(arg: Priv) {} //~ WARN private type in public interface
|
||||
fn f2() -> Priv { panic!() } //~ WARN private type in public interface
|
||||
}
|
||||
extern {
|
||||
pub static ES: Priv; //~ WARN private type in public interface
|
||||
pub fn ef1(arg: Priv); //~ WARN private type in public interface
|
||||
pub fn ef2() -> Priv; //~ WARN private type in public interface
|
||||
}
|
||||
impl PubTr for Pub {
|
||||
type Alias = Priv; //~ WARN private type in public interface
|
||||
}
|
||||
}
|
||||
|
||||
mod traits {
|
||||
trait PrivTr {}
|
||||
pub struct Pub<T>(T);
|
||||
pub trait PubTr {}
|
||||
|
||||
pub type Alias<T: PrivTr> = T; //~ WARN private trait in public interface
|
||||
//~^ WARN trait bounds are not (yet) enforced in type definitions
|
||||
pub trait Tr1: PrivTr {} //~ WARN private trait in public interface
|
||||
pub trait Tr2<T: PrivTr> {} //~ WARN private trait in public interface
|
||||
pub trait Tr3 {
|
||||
type Alias: PrivTr; //~ WARN private trait in public interface
|
||||
fn f<T: PrivTr>(arg: T) {} //~ WARN private trait in public interface
|
||||
}
|
||||
impl<T: PrivTr> Pub<T> {} //~ WARN private trait in public interface
|
||||
impl<T: PrivTr> PubTr for Pub<T> {} //~ WARN private trait in public interface
|
||||
}
|
||||
|
||||
mod traits_where {
|
||||
trait PrivTr {}
|
||||
pub struct Pub<T>(T);
|
||||
pub trait PubTr {}
|
||||
|
||||
pub type Alias<T> where T: PrivTr = T; //~ WARN private trait in public interface
|
||||
pub trait Tr2<T> where T: PrivTr {} //~ WARN private trait in public interface
|
||||
pub trait Tr3 {
|
||||
fn f<T>(arg: T) where T: PrivTr {} //~ WARN private trait in public interface
|
||||
}
|
||||
impl<T> Pub<T> where T: PrivTr {} //~ WARN private trait in public interface
|
||||
impl<T> PubTr for Pub<T> where T: PrivTr {} //~ WARN private trait in public interface
|
||||
}
|
||||
|
||||
mod generics {
|
||||
struct Priv<T = u8>(T);
|
||||
pub struct Pub<T = u8>(T);
|
||||
trait PrivTr<T> {}
|
||||
pub trait PubTr<T> {}
|
||||
|
||||
pub trait Tr1: PrivTr<Pub> {} //~ WARN private trait in public interface
|
||||
pub trait Tr2: PubTr<Priv> {} //~ WARN private type in public interface
|
||||
pub trait Tr3: PubTr<[Priv; 1]> {} //~ WARN private type in public interface
|
||||
pub trait Tr4: PubTr<Pub<Priv>> {} //~ WARN private type in public interface
|
||||
}
|
||||
|
||||
mod impls {
|
||||
struct Priv;
|
||||
pub struct Pub;
|
||||
trait PrivTr {
|
||||
type Alias;
|
||||
}
|
||||
pub trait PubTr {
|
||||
type Alias;
|
||||
}
|
||||
|
||||
impl Priv {
|
||||
pub fn f(arg: Priv) {} // OK
|
||||
}
|
||||
impl PrivTr for Priv {
|
||||
type Alias = Priv; // OK
|
||||
}
|
||||
impl PubTr for Priv {
|
||||
type Alias = Priv; // OK
|
||||
}
|
||||
impl PrivTr for Pub {
|
||||
type Alias = Priv; // OK
|
||||
}
|
||||
impl PubTr for Pub {
|
||||
type Alias = Priv; //~ WARN private type in public interface
|
||||
}
|
||||
}
|
||||
|
||||
mod impls_generics {
|
||||
struct Priv<T = u8>(T);
|
||||
pub struct Pub<T = u8>(T);
|
||||
trait PrivTr<T = u8> {
|
||||
type Alias;
|
||||
}
|
||||
pub trait PubTr<T = u8> {
|
||||
type Alias;
|
||||
}
|
||||
|
||||
impl Priv<Pub> {
|
||||
pub fn f(arg: Priv) {} // OK
|
||||
}
|
||||
impl Pub<Priv> {
|
||||
pub fn f(arg: Priv) {} // OK
|
||||
}
|
||||
impl PrivTr<Pub> for Priv {
|
||||
type Alias = Priv; // OK
|
||||
}
|
||||
impl PubTr<Priv> for Priv {
|
||||
type Alias = Priv; // OK
|
||||
}
|
||||
impl PubTr for Priv<Pub> {
|
||||
type Alias = Priv; // OK
|
||||
}
|
||||
impl PubTr for [Priv; 1] {
|
||||
type Alias = Priv; // OK
|
||||
}
|
||||
impl PubTr for Pub<Priv> {
|
||||
type Alias = Priv; // OK
|
||||
}
|
||||
impl PrivTr<Pub> for Pub {
|
||||
type Alias = Priv; // OK
|
||||
}
|
||||
impl PubTr<Priv> for Pub {
|
||||
type Alias = Priv; // OK
|
||||
}
|
||||
}
|
||||
|
||||
mod aliases_pub {
|
||||
struct Priv;
|
||||
mod m {
|
||||
pub struct Pub1;
|
||||
pub struct Pub2;
|
||||
pub struct Pub3;
|
||||
pub trait PubTr<T = u8> {
|
||||
type Check = u8;
|
||||
}
|
||||
}
|
||||
|
||||
use self::m::Pub1 as PrivUseAlias;
|
||||
use self::m::PubTr as PrivUseAliasTr;
|
||||
type PrivAlias = m::Pub2;
|
||||
trait PrivTr {
|
||||
type AssocAlias = m::Pub3;
|
||||
}
|
||||
impl PrivTr for Priv {}
|
||||
|
||||
pub fn f1(arg: PrivUseAlias) {} // OK
|
||||
|
||||
pub trait Tr1: PrivUseAliasTr {} // OK
|
||||
// This should be OK, if type aliases are substituted
|
||||
pub trait Tr2: PrivUseAliasTr<PrivAlias> {} //~ WARN private type in public interface
|
||||
|
||||
impl PrivAlias {
|
||||
pub fn f(arg: Priv) {} //~ WARN private type in public interface
|
||||
}
|
||||
// This doesn't even parse
|
||||
// impl <Priv as PrivTr>::AssocAlias {
|
||||
// pub fn f(arg: Priv) {} // WARN private type in public interface
|
||||
// }
|
||||
impl PrivUseAliasTr for PrivUseAlias {
|
||||
type Check = Priv; //~ WARN private type in public interface
|
||||
}
|
||||
impl PrivUseAliasTr for PrivAlias {
|
||||
type Check = Priv; //~ WARN private type in public interface
|
||||
}
|
||||
impl PrivUseAliasTr for <Priv as PrivTr>::AssocAlias {
|
||||
type Check = Priv; //~ WARN private type in public interface
|
||||
}
|
||||
}
|
||||
|
||||
mod aliases_priv {
|
||||
struct Priv;
|
||||
|
||||
struct Priv1;
|
||||
struct Priv2;
|
||||
struct Priv3;
|
||||
trait PrivTr1<T = u8> {
|
||||
type Check = u8;
|
||||
}
|
||||
|
||||
use self::Priv1 as PrivUseAlias;
|
||||
use self::PrivTr1 as PrivUseAliasTr;
|
||||
type PrivAlias = Priv2;
|
||||
trait PrivTr {
|
||||
type AssocAlias = Priv3;
|
||||
}
|
||||
impl PrivTr for Priv {}
|
||||
|
||||
pub trait Tr1: PrivUseAliasTr {} //~ WARN private trait in public interface
|
||||
pub trait Tr2: PrivUseAliasTr<PrivAlias> {} //~ WARN private trait in public interface
|
||||
//~^ WARN private type in public interface
|
||||
|
||||
impl PrivUseAlias {
|
||||
pub fn f(arg: Priv) {} // OK
|
||||
}
|
||||
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
|
||||
}
|
||||
impl PrivUseAliasTr for PrivAlias {
|
||||
type Check = Priv; // OK
|
||||
}
|
||||
impl PrivUseAliasTr for <Priv as PrivTr>::AssocAlias {
|
||||
type Check = Priv; // OK
|
||||
}
|
||||
}
|
||||
|
||||
mod aliases_params {
|
||||
struct Priv;
|
||||
type PrivAliasGeneric<T = Priv> = T;
|
||||
type Result<T> = ::std::result::Result<T, Priv>;
|
||||
}
|
||||
|
||||
#[rustc_error]
|
||||
fn main() {} //~ ERROR compilation successful
|
152
src/test/compile-fail/private-in-public.rs
Normal file
152
src/test/compile-fail/private-in-public.rs
Normal file
@ -0,0 +1,152 @@
|
||||
// Copyright 2015 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 public interfaces.
|
||||
// This test also ensures that the checks are performed even inside private modules.
|
||||
|
||||
#![feature(associated_consts)]
|
||||
#![feature(associated_type_defaults)]
|
||||
|
||||
mod types {
|
||||
struct Priv;
|
||||
pub struct Pub;
|
||||
pub trait PubTr {
|
||||
type Alias;
|
||||
}
|
||||
|
||||
pub const C: Priv = Priv; //~ ERROR private type in public interface
|
||||
pub static S: Priv = Priv; //~ ERROR private type in public interface
|
||||
pub fn f1(arg: Priv) {} //~ ERROR private type in public interface
|
||||
pub fn f2() -> Priv { panic!() } //~ ERROR private type in public interface
|
||||
pub struct S1(pub Priv); //~ ERROR private type in public interface
|
||||
pub struct S2 { pub field: Priv } //~ ERROR private type in public interface
|
||||
impl Pub {
|
||||
pub const C: Priv = Priv; //~ ERROR private type in public interface
|
||||
pub fn f1(arg: Priv) {} //~ ERROR private type in public interface
|
||||
pub fn f2() -> Priv { panic!() } //~ ERROR private type in public interface
|
||||
}
|
||||
}
|
||||
|
||||
mod traits {
|
||||
trait PrivTr {}
|
||||
pub struct Pub<T>(T);
|
||||
pub trait PubTr {}
|
||||
|
||||
pub enum E<T: PrivTr> { V(T) } //~ ERROR private trait in public interface
|
||||
pub fn f<T: PrivTr>(arg: T) {} //~ ERROR private trait in public interface
|
||||
pub struct S1<T: PrivTr>(T); //~ ERROR private trait in public interface
|
||||
impl<T: PrivTr> Pub<T> {
|
||||
pub fn f<U: PrivTr>(arg: U) {} //~ ERROR private trait in public interface
|
||||
}
|
||||
}
|
||||
|
||||
mod traits_where {
|
||||
trait PrivTr {}
|
||||
pub struct Pub<T>(T);
|
||||
pub trait PubTr {}
|
||||
|
||||
pub enum E<T> where T: PrivTr { V(T) } //~ ERROR private trait in public interface
|
||||
pub fn f<T>(arg: T) where T: PrivTr {} //~ ERROR private trait in public interface
|
||||
pub struct S1<T>(T) where T: PrivTr; //~ ERROR private trait in public interface
|
||||
impl<T> Pub<T> where T: PrivTr {
|
||||
pub fn f<U>(arg: U) where U: PrivTr {} //~ ERROR private trait in public interface
|
||||
}
|
||||
}
|
||||
|
||||
mod generics {
|
||||
struct Priv<T = u8>(T);
|
||||
pub struct Pub<T = u8>(T);
|
||||
trait PrivTr<T> {}
|
||||
pub trait PubTr<T> {}
|
||||
|
||||
pub fn f1(arg: [Priv; 1]) {} //~ ERROR private type in public interface
|
||||
pub fn f2(arg: Pub<Priv>) {} //~ ERROR private type in public interface
|
||||
pub fn f3(arg: Priv<Pub>) {} //~ ERROR private type in public interface
|
||||
}
|
||||
|
||||
mod impls {
|
||||
struct Priv;
|
||||
pub struct Pub;
|
||||
trait PrivTr {
|
||||
type Alias;
|
||||
}
|
||||
pub trait PubTr {
|
||||
type Alias;
|
||||
}
|
||||
|
||||
impl Pub {
|
||||
pub fn f(arg: Priv) {} //~ ERROR private type in public interface
|
||||
}
|
||||
}
|
||||
|
||||
mod aliases_pub {
|
||||
struct Priv;
|
||||
mod m {
|
||||
pub struct Pub1;
|
||||
pub struct Pub2;
|
||||
pub struct Pub3;
|
||||
pub trait PubTr<T = u8> {
|
||||
type Check = u8;
|
||||
}
|
||||
}
|
||||
|
||||
use self::m::Pub1 as PrivUseAlias;
|
||||
use self::m::PubTr as PrivUseAliasTr;
|
||||
type PrivAlias = m::Pub2;
|
||||
trait PrivTr {
|
||||
type AssocAlias = m::Pub3;
|
||||
}
|
||||
impl PrivTr for Priv {}
|
||||
|
||||
// This should be OK, if type aliases are substituted
|
||||
pub fn f2(arg: PrivAlias) {} //~ ERROR private type in public interface
|
||||
// This should be OK, but associated type aliases are not substituted yet
|
||||
pub fn f3(arg: <Priv as PrivTr>::AssocAlias) {} //~ ERROR private type in public interface
|
||||
|
||||
impl PrivUseAlias {
|
||||
pub fn f(arg: Priv) {} //~ ERROR private type in public interface
|
||||
}
|
||||
}
|
||||
|
||||
mod aliases_priv {
|
||||
struct Priv;
|
||||
|
||||
struct Priv1;
|
||||
struct Priv2;
|
||||
struct Priv3;
|
||||
trait PrivTr1<T = u8> {
|
||||
type Check = u8;
|
||||
}
|
||||
|
||||
use self::Priv1 as PrivUseAlias;
|
||||
use self::PrivTr1 as PrivUseAliasTr;
|
||||
type PrivAlias = Priv2;
|
||||
trait PrivTr {
|
||||
type AssocAlias = Priv3;
|
||||
}
|
||||
impl PrivTr for Priv {}
|
||||
|
||||
pub fn f1(arg: PrivUseAlias) {} //~ ERROR private type in public interface
|
||||
pub fn f2(arg: PrivAlias) {} //~ ERROR private type in public interface
|
||||
pub fn f3(arg: <Priv as PrivTr>::AssocAlias) {} //~ ERROR private type in public interface
|
||||
}
|
||||
|
||||
mod aliases_params {
|
||||
struct Priv;
|
||||
type PrivAliasGeneric<T = Priv> = T;
|
||||
type Result<T> = ::std::result::Result<T, Priv>;
|
||||
|
||||
// This should be OK, if type aliases are substituted
|
||||
pub fn f1(arg: PrivAliasGeneric<u8>) {} //~ ERROR private type in public interface
|
||||
pub fn f2(arg: PrivAliasGeneric) {} //~ ERROR private type in public interface
|
||||
pub fn f3(arg: Result<u8>) {} //~ ERROR private type in public interface
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -8,34 +8,26 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
pub struct PublicType;
|
||||
struct PrivateType;
|
||||
#![feature(rustc_attrs)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
pub trait PublicTrait {
|
||||
type Item;
|
||||
mod m1 {
|
||||
pub use ::E::V; //~ WARN variant `V` is private, and cannot be reexported
|
||||
}
|
||||
|
||||
trait PrivateTrait {
|
||||
type Item;
|
||||
mod m2 {
|
||||
pub use ::E::{V}; //~ WARN variant `V` is private, and cannot be reexported
|
||||
}
|
||||
|
||||
impl PublicTrait for PublicType {
|
||||
type Item = PrivateType; //~ ERROR private type in exported type signature
|
||||
mod m3 {
|
||||
pub use ::E::V::{self}; //~ WARN variant `V` is private, and cannot be reexported
|
||||
}
|
||||
|
||||
// OK
|
||||
impl PublicTrait for PrivateType {
|
||||
type Item = PrivateType;
|
||||
mod m4 {
|
||||
pub use ::E::*; //~ WARN variant `V` is private, and cannot be reexported
|
||||
}
|
||||
|
||||
// OK
|
||||
impl PrivateTrait for PublicType {
|
||||
type Item = PrivateType;
|
||||
}
|
||||
enum E { V }
|
||||
|
||||
// OK
|
||||
impl PrivateTrait for PrivateType {
|
||||
type Item = PrivateType;
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
#[rustc_error]
|
||||
fn main() {} //~ ERROR compilation successful
|
@ -1,67 +0,0 @@
|
||||
// Copyright 2014 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.
|
||||
|
||||
trait Foo {
|
||||
fn dummy(&self) { }
|
||||
}
|
||||
|
||||
pub fn f<
|
||||
T
|
||||
: Foo //~ ERROR private trait in exported type parameter bound
|
||||
>() {}
|
||||
|
||||
pub fn g<T>() where
|
||||
T
|
||||
: Foo //~ ERROR private trait in exported type parameter bound
|
||||
{}
|
||||
|
||||
pub struct S;
|
||||
|
||||
impl S {
|
||||
pub fn f<
|
||||
T
|
||||
: Foo //~ ERROR private trait in exported type parameter bound
|
||||
>() {}
|
||||
|
||||
pub fn g<T>() where
|
||||
T
|
||||
: Foo //~ ERROR private trait in exported type parameter bound
|
||||
{}
|
||||
}
|
||||
|
||||
pub struct S1<
|
||||
T
|
||||
: Foo //~ ERROR private trait in exported type parameter bound
|
||||
> {
|
||||
x: T
|
||||
}
|
||||
|
||||
pub struct S2<T> where
|
||||
T
|
||||
: Foo //~ ERROR private trait in exported type parameter bound
|
||||
{
|
||||
x: T
|
||||
}
|
||||
|
||||
pub enum E1<
|
||||
T
|
||||
: Foo //~ ERROR private trait in exported type parameter bound
|
||||
> {
|
||||
V1(T)
|
||||
}
|
||||
|
||||
pub enum E2<T> where
|
||||
T
|
||||
: Foo //~ ERROR private trait in exported type parameter bound
|
||||
{
|
||||
V2(T)
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -182,7 +182,7 @@ use self::Enum1::{Variant1, Variant2};
|
||||
use std::marker::PhantomData;
|
||||
use std::ptr;
|
||||
|
||||
struct Struct1;
|
||||
pub struct Struct1;
|
||||
struct GenericStruct<T1, T2>(PhantomData<(T1,T2)>);
|
||||
|
||||
enum Enum1 {
|
||||
|
@ -13,11 +13,11 @@
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
struct DeterministicHasher;
|
||||
struct RandomHasher;
|
||||
pub struct DeterministicHasher;
|
||||
pub struct RandomHasher;
|
||||
|
||||
|
||||
struct MyHashMap<K, V, H=DeterministicHasher> {
|
||||
pub struct MyHashMap<K, V, H=DeterministicHasher> {
|
||||
data: PhantomData<(K, V, H)>
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
trait Test { type T; }
|
||||
pub trait Test { type T; }
|
||||
|
||||
impl Test for u32 {
|
||||
type T = i32;
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
@ -8,10 +8,18 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
trait Foo {
|
||||
fn dummy(&self) { }
|
||||
// Functions can return unnameable types
|
||||
|
||||
mod m1 {
|
||||
mod m2 {
|
||||
#[derive(Debug)]
|
||||
pub struct A;
|
||||
}
|
||||
use self::m2::A;
|
||||
pub fn x() -> A { A }
|
||||
}
|
||||
|
||||
pub trait Bar : Foo {} //~ ERROR private trait in exported type
|
||||
|
||||
fn main() {}
|
||||
fn main() {
|
||||
let x = m1::x();
|
||||
println!("{:?}", x);
|
||||
}
|
Loading…
Reference in New Issue
Block a user