Check types for privacy
This commit is contained in:
parent
cd72f2e269
commit
85fb9e0d91
@ -18,13 +18,13 @@
|
||||
|
||||
#![feature(rustc_diagnostic_macros)]
|
||||
|
||||
extern crate rustc;
|
||||
#[macro_use] extern crate rustc;
|
||||
#[macro_use] extern crate syntax;
|
||||
extern crate syntax_pos;
|
||||
|
||||
use rustc::hir::{self, PatKind};
|
||||
use rustc::hir::def::Def;
|
||||
use rustc::hir::def_id::{LOCAL_CRATE, CrateNum, DefId};
|
||||
use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, CrateNum, DefId};
|
||||
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
|
||||
use rustc::hir::itemlikevisit::DeepVisitor;
|
||||
use rustc::lint;
|
||||
@ -537,6 +537,324 @@ impl<'a, 'tcx> Visitor<'tcx> for NamePrivacyVisitor<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Type privacy visitor, checks types for privacy and reports violations.
|
||||
/// Both explicitly written types and inferred types of expressions and patters are checked.
|
||||
/// Checks are performed on "semantic" types regardless of names and their hygiene.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct TypePrivacyVisitor<'a, 'tcx: 'a> {
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
tables: &'a ty::TypeckTables<'tcx>,
|
||||
current_item: DefId,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> {
|
||||
fn def_id_visibility(&self, did: DefId) -> ty::Visibility {
|
||||
match self.tcx.hir.as_local_node_id(did) {
|
||||
Some(node_id) => {
|
||||
let vis = match self.tcx.hir.get(node_id) {
|
||||
hir::map::NodeItem(item) => &item.vis,
|
||||
hir::map::NodeForeignItem(foreign_item) => &foreign_item.vis,
|
||||
hir::map::NodeImplItem(impl_item) => &impl_item.vis,
|
||||
hir::map::NodeTraitItem(..) |
|
||||
hir::map::NodeVariant(..) => {
|
||||
return self.def_id_visibility(self.tcx.hir.get_parent_did(node_id));
|
||||
}
|
||||
hir::map::NodeStructCtor(vdata) => {
|
||||
let struct_node_id = self.tcx.hir.get_parent(node_id);
|
||||
let struct_vis = match self.tcx.hir.get(struct_node_id) {
|
||||
hir::map::NodeItem(item) => &item.vis,
|
||||
node => bug!("unexpected node kind: {:?}", node),
|
||||
};
|
||||
let mut ctor_vis
|
||||
= ty::Visibility::from_hir(struct_vis, struct_node_id, self.tcx);
|
||||
for field in vdata.fields() {
|
||||
let field_vis = ty::Visibility::from_hir(&field.vis, node_id, self.tcx);
|
||||
if ctor_vis.is_at_least(field_vis, self.tcx) {
|
||||
ctor_vis = field_vis;
|
||||
}
|
||||
}
|
||||
return ctor_vis;
|
||||
}
|
||||
node => bug!("unexpected node kind: {:?}", node)
|
||||
};
|
||||
ty::Visibility::from_hir(vis, node_id, self.tcx)
|
||||
}
|
||||
None => self.tcx.sess.cstore.visibility(did),
|
||||
}
|
||||
}
|
||||
|
||||
fn item_is_accessible(&self, did: DefId) -> bool {
|
||||
self.def_id_visibility(did).is_accessible_from(self.current_item, self.tcx)
|
||||
}
|
||||
|
||||
fn check_expr_pat_type(&mut self, id: ast::NodeId, span: Span) -> bool {
|
||||
if let Some(ty) = self.tables.node_id_to_type_opt(id) {
|
||||
self.span = span;
|
||||
ty.visit_with(self)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn check_item(&mut self, item_id: ast::NodeId) -> &mut Self {
|
||||
self.current_item = self.tcx.hir.local_def_id(item_id);
|
||||
self.span = self.tcx.hir.span(item_id);
|
||||
self
|
||||
}
|
||||
|
||||
// Convenience methods for checking item interfaces
|
||||
fn ty(&mut self) -> &mut Self {
|
||||
self.tcx.type_of(self.current_item).visit_with(self);
|
||||
self
|
||||
}
|
||||
|
||||
fn generics(&mut self) -> &mut Self {
|
||||
for def in &self.tcx.generics_of(self.current_item).types {
|
||||
if def.has_default {
|
||||
self.tcx.type_of(def.def_id).visit_with(self);
|
||||
}
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
fn predicates(&mut self) -> &mut Self {
|
||||
self.tcx.predicates_of(self.current_item).visit_with(self);
|
||||
self
|
||||
}
|
||||
|
||||
fn impl_trait_ref(&mut self) -> &mut Self {
|
||||
self.tcx.impl_trait_ref(self.current_item).visit_with(self);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'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 nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
|
||||
NestedVisitorMap::All(&self.tcx.hir)
|
||||
}
|
||||
|
||||
fn visit_nested_body(&mut self, body: hir::BodyId) {
|
||||
let orig_tables = replace(&mut self.tables, self.tcx.body_tables(body));
|
||||
let body = self.tcx.hir.body(body);
|
||||
self.visit_body(body);
|
||||
self.tables = orig_tables;
|
||||
}
|
||||
|
||||
// Check types of expressions
|
||||
fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
|
||||
if self.check_expr_pat_type(expr.id, expr.span) {
|
||||
// Do not check nested expressions if the error already happened.
|
||||
return;
|
||||
}
|
||||
match expr.node {
|
||||
hir::ExprAssign(.., ref rhs) | hir::ExprMatch(ref rhs, ..) => {
|
||||
// Do not report duplicate errors for `x = y` and `match x { ... }`.
|
||||
if self.check_expr_pat_type(rhs.id, rhs.span) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
hir::ExprMethodCall(name, ..) => {
|
||||
// Method calls have to be checked specially.
|
||||
if let Some(method) = self.tables.method_map.get(&ty::MethodCall::expr(expr.id)) {
|
||||
self.span = name.span;
|
||||
if method.ty.visit_with(self) || method.substs.visit_with(self) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
intravisit::walk_expr(self, expr);
|
||||
}
|
||||
|
||||
// Check types of patterns
|
||||
fn visit_pat(&mut self, pattern: &'tcx hir::Pat) {
|
||||
if self.check_expr_pat_type(pattern.id, pattern.span) {
|
||||
// Do not check nested patterns if the error already happened.
|
||||
return;
|
||||
}
|
||||
|
||||
intravisit::walk_pat(self, pattern);
|
||||
}
|
||||
|
||||
fn visit_local(&mut self, local: &'tcx hir::Local) {
|
||||
if let Some(ref init) = local.init {
|
||||
if self.check_expr_pat_type(init.id, init.span) {
|
||||
// Do not report duplicate errors for `let x = y`.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
intravisit::walk_local(self, local);
|
||||
}
|
||||
|
||||
// Check types in item interfaces
|
||||
fn visit_item(&mut self, item: &'tcx hir::Item) {
|
||||
let orig_current_item = self.current_item;
|
||||
|
||||
match item.node {
|
||||
hir::ItemExternCrate(..) | hir::ItemMod(..) |
|
||||
hir::ItemUse(..) | hir::ItemGlobalAsm(..) => {}
|
||||
hir::ItemConst(..) | hir::ItemStatic(..) |
|
||||
hir::ItemTy(..) | hir::ItemFn(..) => {
|
||||
self.check_item(item.id).generics().predicates().ty();
|
||||
}
|
||||
hir::ItemTrait(.., ref trait_item_refs) => {
|
||||
self.check_item(item.id).generics().predicates();
|
||||
for trait_item_ref in trait_item_refs {
|
||||
let mut check = self.check_item(trait_item_ref.id.node_id);
|
||||
check.generics().predicates();
|
||||
if trait_item_ref.kind != hir::AssociatedItemKind::Type ||
|
||||
trait_item_ref.defaultness.has_value() {
|
||||
check.ty();
|
||||
}
|
||||
}
|
||||
}
|
||||
hir::ItemEnum(ref def, _) => {
|
||||
self.check_item(item.id).generics().predicates();
|
||||
for variant in &def.variants {
|
||||
for field in variant.node.data.fields() {
|
||||
self.check_item(field.id).ty();
|
||||
}
|
||||
}
|
||||
}
|
||||
hir::ItemForeignMod(ref foreign_mod) => {
|
||||
for foreign_item in &foreign_mod.items {
|
||||
self.check_item(foreign_item.id).generics().predicates().ty();
|
||||
}
|
||||
}
|
||||
hir::ItemStruct(ref struct_def, _) |
|
||||
hir::ItemUnion(ref struct_def, _) => {
|
||||
self.check_item(item.id).generics().predicates();
|
||||
for field in struct_def.fields() {
|
||||
self.check_item(field.id).ty();
|
||||
}
|
||||
}
|
||||
hir::ItemDefaultImpl(..) => {
|
||||
self.check_item(item.id).impl_trait_ref();
|
||||
}
|
||||
hir::ItemImpl(.., ref trait_ref, _, ref impl_item_refs) => {
|
||||
{
|
||||
let mut check = self.check_item(item.id);
|
||||
check.ty().generics().predicates();
|
||||
if trait_ref.is_some() {
|
||||
check.impl_trait_ref();
|
||||
}
|
||||
}
|
||||
for impl_item_ref in impl_item_refs {
|
||||
let impl_item = self.tcx.hir.impl_item(impl_item_ref.id);
|
||||
self.check_item(impl_item.id).generics().predicates().ty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.current_item = self.tcx.hir.local_def_id(item.id);
|
||||
intravisit::walk_item(self, item);
|
||||
self.current_item = orig_current_item;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> TypeVisitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
|
||||
match ty.sty {
|
||||
ty::TyAdt(&ty::AdtDef { did: def_id, .. }, ..) | ty::TyFnDef(def_id, ..) => {
|
||||
if !self.item_is_accessible(def_id) {
|
||||
let msg = format!("type `{}` is private", ty);
|
||||
self.tcx.sess.span_err(self.span, &msg);
|
||||
return true;
|
||||
}
|
||||
if let ty::TyFnDef(..) = ty.sty {
|
||||
// Inherent static methods don't have self type in substs,
|
||||
// we have to check it additionally.
|
||||
let mut impl_def_id = None;
|
||||
if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
|
||||
if let hir::map::NodeImplItem(..) = self.tcx.hir.get(node_id) {
|
||||
impl_def_id = Some(self.tcx.hir.get_parent_did(node_id));
|
||||
}
|
||||
} else if let Some(Def::Method(..)) = self.tcx.describe_def(def_id) {
|
||||
let candidate_impl_def_id = self.tcx.parent_def_id(def_id)
|
||||
.expect("no parent for method def_id");
|
||||
// `is_none` means it's an impl, not a trait
|
||||
if self.tcx.describe_def(candidate_impl_def_id).is_none() {
|
||||
impl_def_id = Some(candidate_impl_def_id)
|
||||
}
|
||||
}
|
||||
if let Some(impl_def_id) = impl_def_id {
|
||||
let self_ty = self.tcx.type_of(impl_def_id);
|
||||
if self_ty.visit_with(self) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::TyDynamic(ref predicates, ..) => {
|
||||
let is_private = predicates.skip_binder().iter().any(|predicate| {
|
||||
let def_id = match *predicate {
|
||||
ty::ExistentialPredicate::Trait(trait_ref) => trait_ref.def_id,
|
||||
ty::ExistentialPredicate::Projection(proj) => proj.trait_ref.def_id,
|
||||
ty::ExistentialPredicate::AutoTrait(def_id) => def_id,
|
||||
};
|
||||
!self.item_is_accessible(def_id)
|
||||
});
|
||||
if is_private {
|
||||
let msg = format!("type `{}` is private", ty);
|
||||
self.tcx.sess.span_err(self.span, &msg);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
ty::TyAnon(def_id, ..) => {
|
||||
for predicate in &self.tcx.predicates_of(def_id).predicates {
|
||||
let trait_ref = match *predicate {
|
||||
ty::Predicate::Trait(ref poly_trait_predicate) => {
|
||||
Some(poly_trait_predicate.skip_binder().trait_ref)
|
||||
}
|
||||
ty::Predicate::Projection(ref poly_projection_predicate) => {
|
||||
if poly_projection_predicate.skip_binder().ty.visit_with(self) {
|
||||
return true;
|
||||
}
|
||||
Some(poly_projection_predicate.skip_binder().projection_ty.trait_ref)
|
||||
}
|
||||
ty::Predicate::TypeOutlives(..) => None,
|
||||
_ => bug!("unexpected predicate: {:?}", predicate),
|
||||
};
|
||||
if let Some(trait_ref) = trait_ref {
|
||||
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;
|
||||
}
|
||||
// Skip `Self` to avoid infinite recursion
|
||||
for subst in trait_ref.substs.iter().skip(1) {
|
||||
if subst.visit_with(self) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
ty.super_visit_with(self)
|
||||
}
|
||||
|
||||
fn visit_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)
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// Obsolete visitors for checking for private items in public interfaces.
|
||||
/// These visitors are supposed to be kept in frozen state and produce an
|
||||
@ -1225,6 +1543,16 @@ fn privacy_access_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
};
|
||||
intravisit::walk_crate(&mut visitor, krate);
|
||||
|
||||
// Check privacy of explicitly written types and traits as well as
|
||||
// inferred types of expressions and patterns.
|
||||
let mut visitor = TypePrivacyVisitor {
|
||||
tcx: tcx,
|
||||
tables: &ty::TypeckTables::empty(),
|
||||
current_item: DefId::local(CRATE_DEF_INDEX),
|
||||
span: krate.span,
|
||||
};
|
||||
intravisit::walk_crate(&mut visitor, krate);
|
||||
|
||||
// Build up a set of all exported items in the AST. This is a set of all
|
||||
// items which are reachable from external crates based on visibility.
|
||||
let mut visitor = EmbargoVisitor {
|
||||
|
41
src/test/compile-fail/auxiliary/private-inferred-type.rs
Normal file
41
src/test/compile-fail/auxiliary/private-inferred-type.rs
Normal file
@ -0,0 +1,41 @@
|
||||
// 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)]
|
||||
|
||||
fn priv_fn() {}
|
||||
enum PrivEnum { Variant }
|
||||
pub enum PubEnum { Variant }
|
||||
trait PrivTrait { fn method() {} }
|
||||
impl PrivTrait for u8 {}
|
||||
pub trait PubTrait { fn method() {} }
|
||||
impl PubTrait for u8 {}
|
||||
struct PrivTupleStruct(u8);
|
||||
pub struct PubTupleStruct(u8);
|
||||
impl PubTupleStruct { fn method() {} }
|
||||
|
||||
struct Priv;
|
||||
pub type Alias = Priv;
|
||||
pub struct Pub<T = Alias>(pub T);
|
||||
|
||||
impl Pub<Priv> {
|
||||
pub fn static_method() {}
|
||||
}
|
||||
|
||||
pub macro m() {
|
||||
priv_fn;
|
||||
PrivEnum::Variant;
|
||||
PubEnum::Variant;
|
||||
<u8 as PrivTrait>::method;
|
||||
<u8 as PubTrait>::method;
|
||||
PrivTupleStruct;
|
||||
PubTupleStruct;
|
||||
Pub::static_method;
|
||||
}
|
@ -22,11 +22,11 @@ mod foo {
|
||||
x: i32,
|
||||
}
|
||||
|
||||
let s = S { x: 0 };
|
||||
let _ = s.x;
|
||||
let s = S { x: 0 }; //~ ERROR type `foo::S` is private
|
||||
let _ = s.x; //~ ERROR type `foo::S` is private
|
||||
|
||||
let t = T(0);
|
||||
let _ = t.0;
|
||||
let t = T(0); //~ ERROR type `foo::T` is private
|
||||
let _ = t.0; //~ ERROR type `foo::T` is private
|
||||
|
||||
let s = $S { $x: 0, x: 1 };
|
||||
assert_eq!((s.$x, s.x), (0, 1));
|
@ -19,7 +19,7 @@ mod foo {
|
||||
}
|
||||
|
||||
pub macro m() {
|
||||
let _: () = S.f();
|
||||
let _: () = S.f(); //~ ERROR type `fn(&foo::S) {foo::S::f}` is private
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,8 @@
|
||||
|
||||
// aux-build:intercrate.rs
|
||||
|
||||
// error-pattern:type `fn() -> u32 {intercrate::foo::bar::f}` is private
|
||||
|
||||
#![feature(decl_macro)]
|
||||
|
||||
extern crate intercrate;
|
28
src/test/compile-fail/private-inferred-type-1.rs
Normal file
28
src/test/compile-fail/private-inferred-type-1.rs
Normal file
@ -0,0 +1,28 @@
|
||||
// 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.
|
||||
|
||||
trait Arr0 {
|
||||
fn arr0_secret(&self);
|
||||
}
|
||||
trait TyParam {
|
||||
fn ty_param_secret(&self);
|
||||
}
|
||||
|
||||
mod m {
|
||||
struct Priv;
|
||||
|
||||
impl ::Arr0 for [Priv; 0] { fn arr0_secret(&self) {} }
|
||||
impl ::TyParam for Option<Priv> { fn ty_param_secret(&self) {} }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
[].arr0_secret(); //~ ERROR type `m::Priv` is private
|
||||
None.ty_param_secret(); //~ ERROR type `m::Priv` is private
|
||||
}
|
29
src/test/compile-fail/private-inferred-type-2.rs
Normal file
29
src/test/compile-fail/private-inferred-type-2.rs
Normal file
@ -0,0 +1,29 @@
|
||||
// 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.
|
||||
|
||||
// aux-build:private-inferred-type.rs
|
||||
|
||||
extern crate private_inferred_type as ext;
|
||||
|
||||
mod m {
|
||||
struct Priv;
|
||||
pub struct Pub<T>(pub T);
|
||||
|
||||
impl Pub<Priv> {
|
||||
pub fn get_priv() -> Priv { Priv }
|
||||
pub fn static_method() {}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
m::Pub::get_priv; //~ ERROR type `m::Priv` is private
|
||||
m::Pub::static_method; //~ ERROR type `m::Priv` is private
|
||||
ext::Pub::static_method; //~ ERROR type `ext::Priv` is private
|
||||
}
|
26
src/test/compile-fail/private-inferred-type-3.rs
Normal file
26
src/test/compile-fail/private-inferred-type-3.rs
Normal file
@ -0,0 +1,26 @@
|
||||
// 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.
|
||||
|
||||
// aux-build:private-inferred-type.rs
|
||||
|
||||
// error-pattern:type `fn() {ext::priv_fn}` 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
|
||||
// error-pattern:type `fn(u8) -> ext::PubTupleStruct {ext::PubTupleStruct::{{constructor}}}` is priv
|
||||
// error-pattern:type `ext::Priv` is private
|
||||
|
||||
#![feature(decl_macro)]
|
||||
|
||||
extern crate private_inferred_type as ext;
|
||||
|
||||
fn main() {
|
||||
ext::m!();
|
||||
}
|
83
src/test/compile-fail/private-inferred-type.rs
Normal file
83
src/test/compile-fail/private-inferred-type.rs
Normal file
@ -0,0 +1,83 @@
|
||||
// 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(conservative_impl_trait)]
|
||||
#![feature(decl_macro)]
|
||||
|
||||
mod m {
|
||||
fn priv_fn() {}
|
||||
enum PrivEnum { Variant }
|
||||
pub enum PubEnum { Variant }
|
||||
trait PrivTrait { fn method() {} }
|
||||
impl PrivTrait for u8 {}
|
||||
pub trait PubTrait { fn method() {} }
|
||||
impl PubTrait for u8 {}
|
||||
struct PrivTupleStruct(u8);
|
||||
pub struct PubTupleStruct(u8);
|
||||
impl PubTupleStruct { fn method() {} }
|
||||
|
||||
struct Priv;
|
||||
pub type Alias = Priv;
|
||||
pub struct Pub<T = Alias>(pub T);
|
||||
|
||||
impl Pub<Priv> {
|
||||
pub fn static_method() {}
|
||||
}
|
||||
|
||||
pub macro m() {
|
||||
priv_fn; //~ ERROR type `fn() {m::priv_fn}` is private
|
||||
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
|
||||
<u8 as PubTrait>::method; // OK
|
||||
PrivTupleStruct;
|
||||
//~^ ERROR type `fn(u8) -> m::PrivTupleStruct {m::PrivTupleStruct::{{constructor}}}` is priv
|
||||
PubTupleStruct;
|
||||
//~^ ERROR type `fn(u8) -> m::PubTupleStruct {m::PubTupleStruct::{{constructor}}}` is privat
|
||||
Pub::static_method; //~ ERROR type `m::Priv` is private
|
||||
}
|
||||
|
||||
trait Trait {}
|
||||
pub trait TraitWithTyParam<T> {}
|
||||
pub trait TraitWithAssocTy { type X; }
|
||||
impl Trait for u8 {}
|
||||
impl<T> TraitWithTyParam<T> for u8 {}
|
||||
impl TraitWithAssocTy for u8 { type X = Priv; }
|
||||
|
||||
pub fn leak_anon1() -> impl Trait + 'static { 0 }
|
||||
pub fn leak_anon2() -> impl TraitWithTyParam<Alias> { 0 }
|
||||
pub fn leak_anon3() -> impl TraitWithAssocTy<X = Alias> { 0 }
|
||||
|
||||
pub fn leak_dyn1() -> Box<Trait + 'static> { Box::new(0) }
|
||||
pub fn leak_dyn2() -> Box<TraitWithTyParam<Alias>> { Box::new(0) }
|
||||
pub fn leak_dyn3() -> Box<TraitWithAssocTy<X = Alias>> { Box::new(0) }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
m::Alias {}; //~ ERROR type `m::Priv` is private
|
||||
m::Pub { 0: m::Alias {} }; //~ ERROR type `m::Priv` is private
|
||||
m::m!();
|
||||
|
||||
m::leak_anon1(); //~ ERROR trait `m::Trait` is private
|
||||
m::leak_anon2(); //~ ERROR type `m::Priv` is private
|
||||
m::leak_anon3(); //~ ERROR type `m::Priv` is private
|
||||
|
||||
m::leak_dyn1(); //~ ERROR type `m::Trait + 'static` is private
|
||||
m::leak_dyn2(); //~ ERROR type `m::Priv` is private
|
||||
m::leak_dyn3(); //~ ERROR type `m::Priv` is private
|
||||
|
||||
// Check that messages are not duplicated for various kinds of assignments
|
||||
let a = m::Alias {}; //~ ERROR type `m::Priv` is private
|
||||
let mut b = a; //~ ERROR type `m::Priv` is private
|
||||
b = a; //~ ERROR type `m::Priv` is private
|
||||
match a { //~ ERROR type `m::Priv` is private
|
||||
_ => {}
|
||||
}
|
||||
}
|
37
src/test/compile-fail/private-type-in-interface.rs
Normal file
37
src/test/compile-fail/private-type-in-interface.rs
Normal file
@ -0,0 +1,37 @@
|
||||
// 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.
|
||||
|
||||
// aux-build:private-inferred-type.rs
|
||||
|
||||
#![feature(conservative_impl_trait)]
|
||||
|
||||
extern crate private_inferred_type as ext;
|
||||
|
||||
mod m {
|
||||
struct Priv;
|
||||
pub type Alias = Priv;
|
||||
}
|
||||
|
||||
fn f(_: m::Alias) {} //~ ERROR type `m::Priv` is private
|
||||
//~^ ERROR type `m::Priv` is private
|
||||
fn f_ext(_: ext::Alias) {} //~ ERROR type `ext::Priv` is private
|
||||
//~^ ERROR type `ext::Priv` is private
|
||||
|
||||
trait Tr1 {}
|
||||
impl m::Alias {} //~ ERROR type `m::Priv` is private
|
||||
impl Tr1 for ext::Alias {} //~ ERROR type `ext::Priv` is private
|
||||
//~^ ERROR type `ext::Priv` is private
|
||||
|
||||
trait Tr2<T> {}
|
||||
impl<T> Tr2<T> for u8 {}
|
||||
fn g() -> impl Tr2<m::Alias> { 0 } //~ ERROR type `m::Priv` is private
|
||||
fn g_ext() -> impl Tr2<ext::Alias> { 0 } //~ ERROR type `ext::Priv` is private
|
||||
|
||||
fn main() {}
|
Loading…
Reference in New Issue
Block a user