Auto merge of #46083 - petrochenkov:morepriv, r=nikomatsakis
Type privacy polishing Various preparations before implementing https://github.com/rust-lang/rfcs/pull/2145 containing final minor breaking changes (mostly for unstable code or code using `allow(private_in_public)`). (Continuation of https://github.com/rust-lang/rust/pull/42125, https://github.com/rust-lang/rust/pull/44633 and https://github.com/rust-lang/rust/pull/41332.) It would be good to run crater on this. r? @eddyb
This commit is contained in:
commit
a12706ca71
18 changed files with 655 additions and 135 deletions
|
|
@ -258,8 +258,13 @@ impl Path {
|
|||
|
||||
impl fmt::Debug for Path {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "path({})",
|
||||
print::to_string(print::NO_ANN, |s| s.print_path(self, false)))
|
||||
write!(f, "path({})", print::to_string(print::NO_ANN, |s| s.print_path(self, false)))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Path {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", print::to_string(print::NO_ANN, |s| s.print_path(self, false)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -614,6 +614,7 @@ struct TypePrivacyVisitor<'a, 'tcx: 'a> {
|
|||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
tables: &'a ty::TypeckTables<'tcx>,
|
||||
current_item: DefId,
|
||||
in_body: bool,
|
||||
span: Span,
|
||||
empty_tables: &'a ty::TypeckTables<'tcx>,
|
||||
}
|
||||
|
|
@ -671,10 +672,8 @@ impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> {
|
|||
// Take node ID of an expression or pattern and check its type for privacy.
|
||||
fn check_expr_pat_type(&mut self, id: hir::HirId, span: Span) -> bool {
|
||||
self.span = span;
|
||||
if let Some(ty) = self.tables.node_id_to_type_opt(id) {
|
||||
if ty.visit_with(self) {
|
||||
return true;
|
||||
}
|
||||
if self.tables.node_id_to_type(id).visit_with(self) {
|
||||
return true;
|
||||
}
|
||||
if self.tables.node_substs(id).visit_with(self) {
|
||||
return true;
|
||||
|
|
@ -688,6 +687,16 @@ impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> {
|
|||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn check_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)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
|
||||
|
|
@ -699,16 +708,18 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
|
|||
|
||||
fn visit_nested_body(&mut self, body: hir::BodyId) {
|
||||
let orig_tables = replace(&mut self.tables, self.tcx.body_tables(body));
|
||||
let orig_in_body = replace(&mut self.in_body, true);
|
||||
let body = self.tcx.hir.body(body);
|
||||
self.visit_body(body);
|
||||
self.tables = orig_tables;
|
||||
self.in_body = orig_in_body;
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty) {
|
||||
self.span = hir_ty.span;
|
||||
if let Some(ty) = self.tables.node_id_to_type_opt(hir_ty.hir_id) {
|
||||
if self.in_body {
|
||||
// Types in bodies.
|
||||
if ty.visit_with(self) {
|
||||
if self.tables.node_id_to_type(hir_ty.hir_id).visit_with(self) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -724,10 +735,21 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn visit_trait_ref(&mut self, trait_ref: &'tcx hir::TraitRef) {
|
||||
if !self.item_is_accessible(trait_ref.path.def.def_id()) {
|
||||
let msg = format!("trait `{:?}` is private", trait_ref.path);
|
||||
self.tcx.sess.span_err(self.span, &msg);
|
||||
return;
|
||||
self.span = trait_ref.path.span;
|
||||
if !self.in_body {
|
||||
// Avoid calling `hir_trait_to_predicates` in bodies, it will ICE.
|
||||
// The traits' privacy in bodies is already checked as a part of trait object types.
|
||||
let (principal, projections) =
|
||||
rustc_typeck::hir_trait_to_predicates(self.tcx, trait_ref);
|
||||
if self.check_trait_ref(*principal.skip_binder()) {
|
||||
return;
|
||||
}
|
||||
for poly_predicate in projections {
|
||||
let tcx = self.tcx;
|
||||
if self.check_trait_ref(poly_predicate.skip_binder().projection_ty.trait_ref(tcx)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
intravisit::walk_trait_ref(self, trait_ref);
|
||||
|
|
@ -760,19 +782,35 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
|
|||
intravisit::walk_expr(self, expr);
|
||||
}
|
||||
|
||||
// Prohibit access to associated items with insufficient nominal visibility.
|
||||
//
|
||||
// Additionally, until better reachability analysis for macros 2.0 is available,
|
||||
// we prohibit access to private statics from other crates, this allows to give
|
||||
// more code internal visibility at link time. (Access to private functions
|
||||
// is already prohibited by type privacy for funciton types.)
|
||||
fn visit_qpath(&mut self, qpath: &'tcx hir::QPath, id: ast::NodeId, span: Span) {
|
||||
// Inherent associated constants don't have self type in substs,
|
||||
// we have to check it additionally.
|
||||
if let hir::QPath::TypeRelative(..) = *qpath {
|
||||
let hir_id = self.tcx.hir.node_to_hir_id(id);
|
||||
if let Some(def) = self.tables.type_dependent_defs().get(hir_id).cloned() {
|
||||
if let Some(assoc_item) = self.tcx.opt_associated_item(def.def_id()) {
|
||||
if let ty::ImplContainer(impl_def_id) = assoc_item.container {
|
||||
if self.tcx.type_of(impl_def_id).visit_with(self) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
let def = match *qpath {
|
||||
hir::QPath::Resolved(_, ref path) => match path.def {
|
||||
Def::Method(..) | Def::AssociatedConst(..) |
|
||||
Def::AssociatedTy(..) | Def::Static(..) => Some(path.def),
|
||||
_ => None,
|
||||
}
|
||||
hir::QPath::TypeRelative(..) => {
|
||||
let hir_id = self.tcx.hir.node_to_hir_id(id);
|
||||
self.tables.type_dependent_defs().get(hir_id).cloned()
|
||||
}
|
||||
};
|
||||
if let Some(def) = def {
|
||||
let def_id = def.def_id();
|
||||
let is_local_static = if let Def::Static(..) = def { def_id.is_local() } else { false };
|
||||
if !self.item_is_accessible(def_id) && !is_local_static {
|
||||
let name = match *qpath {
|
||||
hir::QPath::Resolved(_, ref path) => format!("{}", path),
|
||||
hir::QPath::TypeRelative(_, ref segment) => segment.name.to_string(),
|
||||
};
|
||||
let msg = format!("{} `{}` is private", def.kind_name(), name);
|
||||
self.tcx.sess.span_err(span, &msg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -807,9 +845,11 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
|
|||
item.id,
|
||||
&mut self.tables,
|
||||
self.empty_tables);
|
||||
let orig_in_body = replace(&mut self.in_body, false);
|
||||
self.current_item = self.tcx.hir.local_def_id(item.id);
|
||||
intravisit::walk_item(self, item);
|
||||
self.tables = orig_tables;
|
||||
self.in_body = orig_in_body;
|
||||
self.current_item = orig_current_item;
|
||||
}
|
||||
|
||||
|
|
@ -869,13 +909,8 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
ty::TyProjection(ref proj) => {
|
||||
let trait_ref = proj.trait_ref(self.tcx);
|
||||
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;
|
||||
}
|
||||
if trait_ref.super_visit_with(self) {
|
||||
let tcx = self.tcx;
|
||||
if self.check_trait_ref(proj.trait_ref(tcx)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1278,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> {
|
||||
|
|
@ -1338,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,
|
||||
|
|
@ -1393,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");
|
||||
|
|
@ -1454,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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1494,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 &&
|
||||
|
|
@ -1544,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;
|
||||
|
|
@ -1562,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;
|
||||
|
|
@ -1629,6 +1669,7 @@ fn privacy_access_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
tcx,
|
||||
tables: &empty_tables,
|
||||
current_item: DefId::local(CRATE_DEF_INDEX),
|
||||
in_body: false,
|
||||
span: krate.span,
|
||||
empty_tables: &empty_tables,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -347,13 +347,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn instantiate_poly_trait_ref(&self,
|
||||
ast_trait_ref: &hir::PolyTraitRef,
|
||||
pub(super) fn instantiate_poly_trait_ref_inner(&self,
|
||||
trait_ref: &hir::TraitRef,
|
||||
self_ty: Ty<'tcx>,
|
||||
poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
|
||||
poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>,
|
||||
speculative: bool)
|
||||
-> ty::PolyTraitRef<'tcx>
|
||||
{
|
||||
let trait_ref = &ast_trait_ref.trait_ref;
|
||||
let trait_def_id = self.trait_def_id(trait_ref);
|
||||
|
||||
debug!("ast_path_to_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id);
|
||||
|
|
@ -370,7 +370,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
poly_projections.extend(assoc_bindings.iter().filter_map(|binding| {
|
||||
// specify type to assert that error was already reported in Err case:
|
||||
let predicate: Result<_, ErrorReported> =
|
||||
self.ast_type_binding_to_poly_projection_predicate(poly_trait_ref, binding);
|
||||
self.ast_type_binding_to_poly_projection_predicate(trait_ref.ref_id, poly_trait_ref,
|
||||
binding, speculative);
|
||||
predicate.ok() // ok to ignore Err() because ErrorReported (see above)
|
||||
}));
|
||||
|
||||
|
|
@ -379,6 +380,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
poly_trait_ref
|
||||
}
|
||||
|
||||
pub fn instantiate_poly_trait_ref(&self,
|
||||
poly_trait_ref: &hir::PolyTraitRef,
|
||||
self_ty: Ty<'tcx>,
|
||||
poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
|
||||
-> ty::PolyTraitRef<'tcx>
|
||||
{
|
||||
self.instantiate_poly_trait_ref_inner(&poly_trait_ref.trait_ref, self_ty,
|
||||
poly_projections, false)
|
||||
}
|
||||
|
||||
fn ast_path_to_mono_trait_ref(&self,
|
||||
span: Span,
|
||||
trait_def_id: DefId,
|
||||
|
|
@ -442,82 +453,87 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
|
|||
|
||||
fn ast_type_binding_to_poly_projection_predicate(
|
||||
&self,
|
||||
ref_id: ast::NodeId,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
binding: &ConvertedBinding<'tcx>)
|
||||
binding: &ConvertedBinding<'tcx>,
|
||||
speculative: bool)
|
||||
-> Result<ty::PolyProjectionPredicate<'tcx>, ErrorReported>
|
||||
{
|
||||
let tcx = self.tcx();
|
||||
|
||||
// Given something like `U : SomeTrait<T=X>`, we want to produce a
|
||||
// predicate like `<U as SomeTrait>::T = X`. This is somewhat
|
||||
// subtle in the event that `T` is defined in a supertrait of
|
||||
// `SomeTrait`, because in that case we need to upcast.
|
||||
//
|
||||
// That is, consider this case:
|
||||
//
|
||||
// ```
|
||||
// trait SubTrait : SuperTrait<int> { }
|
||||
// trait SuperTrait<A> { type T; }
|
||||
//
|
||||
// ... B : SubTrait<T=foo> ...
|
||||
// ```
|
||||
//
|
||||
// We want to produce `<B as SuperTrait<int>>::T == foo`.
|
||||
if !speculative {
|
||||
// Given something like `U : SomeTrait<T=X>`, we want to produce a
|
||||
// predicate like `<U as SomeTrait>::T = X`. This is somewhat
|
||||
// subtle in the event that `T` is defined in a supertrait of
|
||||
// `SomeTrait`, because in that case we need to upcast.
|
||||
//
|
||||
// That is, consider this case:
|
||||
//
|
||||
// ```
|
||||
// trait SubTrait : SuperTrait<int> { }
|
||||
// trait SuperTrait<A> { type T; }
|
||||
//
|
||||
// ... B : SubTrait<T=foo> ...
|
||||
// ```
|
||||
//
|
||||
// We want to produce `<B as SuperTrait<int>>::T == foo`.
|
||||
|
||||
// Find any late-bound regions declared in `ty` that are not
|
||||
// declared in the trait-ref. These are not wellformed.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
|
||||
// for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
|
||||
let late_bound_in_trait_ref = tcx.collect_constrained_late_bound_regions(&trait_ref);
|
||||
let late_bound_in_ty = tcx.collect_referenced_late_bound_regions(&ty::Binder(binding.ty));
|
||||
debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref);
|
||||
debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
|
||||
for br in late_bound_in_ty.difference(&late_bound_in_trait_ref) {
|
||||
let br_name = match *br {
|
||||
ty::BrNamed(_, name) => name,
|
||||
_ => {
|
||||
span_bug!(
|
||||
binding.span,
|
||||
"anonymous bound region {:?} in binding but not trait ref",
|
||||
br);
|
||||
}
|
||||
};
|
||||
struct_span_err!(tcx.sess,
|
||||
binding.span,
|
||||
E0582,
|
||||
"binding for associated type `{}` references lifetime `{}`, \
|
||||
which does not appear in the trait input types",
|
||||
binding.item_name, br_name)
|
||||
.emit();
|
||||
// Find any late-bound regions declared in `ty` that are not
|
||||
// declared in the trait-ref. These are not wellformed.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
|
||||
// for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
|
||||
let late_bound_in_trait_ref = tcx.collect_constrained_late_bound_regions(&trait_ref);
|
||||
let late_bound_in_ty =
|
||||
tcx.collect_referenced_late_bound_regions(&ty::Binder(binding.ty));
|
||||
debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref);
|
||||
debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
|
||||
for br in late_bound_in_ty.difference(&late_bound_in_trait_ref) {
|
||||
let br_name = match *br {
|
||||
ty::BrNamed(_, name) => name,
|
||||
_ => {
|
||||
span_bug!(
|
||||
binding.span,
|
||||
"anonymous bound region {:?} in binding but not trait ref",
|
||||
br);
|
||||
}
|
||||
};
|
||||
struct_span_err!(tcx.sess,
|
||||
binding.span,
|
||||
E0582,
|
||||
"binding for associated type `{}` references lifetime `{}`, \
|
||||
which does not appear in the trait input types",
|
||||
binding.item_name, br_name)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
// Simple case: X is defined in the current trait.
|
||||
if self.trait_defines_associated_type_named(trait_ref.def_id(), binding.item_name) {
|
||||
return Ok(trait_ref.map_bound(|trait_ref| {
|
||||
ty::ProjectionPredicate {
|
||||
projection_ty: ty::ProjectionTy::from_ref_and_name(
|
||||
tcx,
|
||||
trait_ref,
|
||||
binding.item_name,
|
||||
),
|
||||
ty: binding.ty,
|
||||
}
|
||||
}));
|
||||
let candidate = if self.trait_defines_associated_type_named(trait_ref.def_id(),
|
||||
binding.item_name) {
|
||||
// Simple case: X is defined in the current trait.
|
||||
Ok(trait_ref)
|
||||
} else {
|
||||
// Otherwise, we have to walk through the supertraits to find
|
||||
// those that do.
|
||||
let candidates = traits::supertraits(tcx, trait_ref).filter(|r| {
|
||||
self.trait_defines_associated_type_named(r.def_id(), binding.item_name)
|
||||
});
|
||||
self.one_bound_for_assoc_type(candidates, &trait_ref.to_string(),
|
||||
binding.item_name, binding.span)
|
||||
}?;
|
||||
|
||||
let (assoc_ident, def_scope) = tcx.adjust(binding.item_name, candidate.def_id(), ref_id);
|
||||
let assoc_ty = tcx.associated_items(candidate.def_id()).find(|i| {
|
||||
i.kind == ty::AssociatedKind::Type && i.name.to_ident() == assoc_ident
|
||||
}).expect("missing associated type");
|
||||
|
||||
if !assoc_ty.vis.is_accessible_from(def_scope, tcx) {
|
||||
let msg = format!("associated type `{}` is private", binding.item_name);
|
||||
tcx.sess.span_err(binding.span, &msg);
|
||||
}
|
||||
|
||||
// Otherwise, we have to walk through the supertraits to find
|
||||
// those that do.
|
||||
let candidates =
|
||||
traits::supertraits(tcx, trait_ref.clone())
|
||||
.filter(|r| self.trait_defines_associated_type_named(r.def_id(), binding.item_name));
|
||||
|
||||
let candidate = self.one_bound_for_assoc_type(candidates,
|
||||
&trait_ref.to_string(),
|
||||
binding.item_name,
|
||||
binding.span)?;
|
||||
tcx.check_stability(assoc_ty.def_id, ref_id, binding.span);
|
||||
|
||||
Ok(candidate.map_bound(|trait_ref| {
|
||||
ty::ProjectionPredicate {
|
||||
|
|
|
|||
|
|
@ -349,7 +349,22 @@ pub fn hir_ty_to_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir_ty: &hir::Ty) ->
|
|||
let env_node_id = tcx.hir.get_parent(hir_ty.id);
|
||||
let env_def_id = tcx.hir.local_def_id(env_node_id);
|
||||
let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id);
|
||||
item_cx.to_ty(hir_ty)
|
||||
astconv::AstConv::ast_ty_to_ty(&item_cx, hir_ty)
|
||||
}
|
||||
|
||||
pub fn hir_trait_to_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir_trait: &hir::TraitRef)
|
||||
-> (ty::PolyTraitRef<'tcx>, Vec<ty::PolyProjectionPredicate<'tcx>>) {
|
||||
// In case there are any projections etc, find the "environment"
|
||||
// def-id that will be used to determine the traits/predicates in
|
||||
// scope. This is derived from the enclosing item-like thing.
|
||||
let env_node_id = tcx.hir.get_parent(hir_trait.ref_id);
|
||||
let env_def_id = tcx.hir.local_def_id(env_node_id);
|
||||
let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id);
|
||||
let mut projections = Vec::new();
|
||||
let principal = astconv::AstConv::instantiate_poly_trait_ref_inner(
|
||||
&item_cx, hir_trait, tcx.types.err, &mut projections, true
|
||||
);
|
||||
(principal, projections)
|
||||
}
|
||||
|
||||
__build_diagnostic_array! { librustc_typeck, DIAGNOSTICS }
|
||||
|
|
|
|||
|
|
@ -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() {}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#![feature(decl_macro)]
|
||||
|
||||
fn priv_fn() {}
|
||||
static PRIV_STATIC: u8 = 0;
|
||||
enum PrivEnum { Variant }
|
||||
pub enum PubEnum { Variant }
|
||||
trait PrivTrait { fn method() {} }
|
||||
|
|
@ -34,6 +35,7 @@ impl Pub<u8> {
|
|||
|
||||
pub macro m() {
|
||||
priv_fn;
|
||||
PRIV_STATIC;
|
||||
PrivEnum::Variant;
|
||||
PubEnum::Variant;
|
||||
<u8 as PrivTrait>::method;
|
||||
|
|
|
|||
|
|
@ -8,15 +8,12 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![deny(private_in_public)]
|
||||
#![allow(unused)]
|
||||
|
||||
struct SemiPriv;
|
||||
|
||||
mod m1 {
|
||||
struct Priv;
|
||||
impl ::SemiPriv {
|
||||
pub fn f(_: Priv) {} //~ ERROR private type `m1::Priv` in public interface
|
||||
pub fn f(_: Priv) {} //~ WARN private type `m1::Priv` in public interface
|
||||
//~^ WARNING hard error
|
||||
}
|
||||
|
||||
|
|
@ -29,7 +26,6 @@ mod m2 {
|
|||
struct Priv;
|
||||
impl ::std::ops::Deref for ::SemiPriv {
|
||||
type Target = Priv; //~ ERROR private type `m2::Priv` in public interface
|
||||
//~^ WARNING hard error
|
||||
fn deref(&self) -> &Self::Target { unimplemented!() }
|
||||
}
|
||||
|
||||
|
|
@ -47,7 +43,6 @@ mod m3 {
|
|||
struct Priv;
|
||||
impl ::SemiPrivTrait for () {
|
||||
type Assoc = Priv; //~ ERROR private type `m3::Priv` in public interface
|
||||
//~^ WARNING hard error
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -108,6 +108,11 @@ mod cross_crate {
|
|||
struct S1<T: TraitWithAssociatedTypes>(T::TypeUnstable);
|
||||
struct S2<T: TraitWithAssociatedTypes>(T::TypeDeprecated);
|
||||
//~^ WARN use of deprecated item 'lint_stability::TraitWithAssociatedTypes::TypeDeprecated': text
|
||||
type A = TraitWithAssociatedTypes<
|
||||
TypeUnstable = u8,
|
||||
TypeDeprecated = u16,
|
||||
//~^ WARN use of deprecated item 'lint_stability::TraitWithAssociatedTypes::TypeDeprecated'
|
||||
>;
|
||||
|
||||
let _ = DeprecatedStruct { //~ WARN use of deprecated item 'lint_stability::DeprecatedStruct'
|
||||
i: 0 //~ WARN use of deprecated item 'lint_stability::DeprecatedStruct::i'
|
||||
|
|
|
|||
|
|
@ -96,6 +96,10 @@ mod cross_crate {
|
|||
struct S1<T: TraitWithAssociatedTypes>(T::TypeUnstable);
|
||||
//~^ ERROR use of unstable library feature
|
||||
struct S2<T: TraitWithAssociatedTypes>(T::TypeDeprecated);
|
||||
type A = TraitWithAssociatedTypes<
|
||||
TypeUnstable = u8, //~ ERROR use of unstable library feature
|
||||
TypeDeprecated = u16,
|
||||
>;
|
||||
|
||||
let _ = DeprecatedStruct {
|
||||
i: 0
|
||||
|
|
|
|||
|
|
@ -0,0 +1,122 @@
|
|||
// 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, associated_type_defaults)]
|
||||
#![allow(unused, private_in_public)]
|
||||
|
||||
mod priv_nominal {
|
||||
pub struct Pub;
|
||||
impl Pub {
|
||||
fn method(&self) {}
|
||||
const CONST: u8 = 0;
|
||||
// type AssocTy = u8;
|
||||
}
|
||||
|
||||
pub macro mac() {
|
||||
let value = Pub::method;
|
||||
//~^ ERROR type `for<'r> fn(&'r priv_nominal::Pub) {priv_nominal::Pub::method}` is private
|
||||
value;
|
||||
//~^ ERROR type `for<'r> fn(&'r priv_nominal::Pub) {priv_nominal::Pub::method}` is private
|
||||
Pub.method();
|
||||
//~^ ERROR type `for<'r> fn(&'r priv_nominal::Pub) {priv_nominal::Pub::method}` is private
|
||||
Pub::CONST;
|
||||
//~^ ERROR associated constant `CONST` is private
|
||||
// let _: Pub::AssocTy;
|
||||
// pub type InSignatureTy = Pub::AssocTy;
|
||||
}
|
||||
}
|
||||
fn priv_nominal() {
|
||||
priv_nominal::mac!();
|
||||
}
|
||||
|
||||
mod priv_signature {
|
||||
struct Priv;
|
||||
pub struct Pub;
|
||||
impl Pub {
|
||||
pub fn method(&self, arg: Priv) {}
|
||||
}
|
||||
|
||||
pub macro mac() {
|
||||
let value = Pub::method;
|
||||
//~^ ERROR type `priv_signature::Priv` is private
|
||||
value;
|
||||
//~^ ERROR type `priv_signature::Priv` is private
|
||||
Pub.method(loop {});
|
||||
//~^ ERROR type `priv_signature::Priv` is private
|
||||
}
|
||||
}
|
||||
fn priv_signature() {
|
||||
priv_signature::mac!();
|
||||
}
|
||||
|
||||
mod priv_substs {
|
||||
struct Priv;
|
||||
pub struct Pub;
|
||||
impl Pub {
|
||||
pub fn method<T>(&self) {}
|
||||
}
|
||||
|
||||
pub macro mac() {
|
||||
let value = Pub::method::<Priv>;
|
||||
//~^ ERROR type `priv_substs::Priv` is private
|
||||
value;
|
||||
//~^ ERROR type `priv_substs::Priv` is private
|
||||
Pub.method::<Priv>();
|
||||
//~^ ERROR type `priv_substs::Priv` is private
|
||||
}
|
||||
}
|
||||
fn priv_substs() {
|
||||
priv_substs::mac!();
|
||||
}
|
||||
|
||||
mod priv_parent_substs {
|
||||
struct Priv;
|
||||
pub struct Pub<T = Priv>(T);
|
||||
impl Pub<Priv> {
|
||||
pub fn method(&self) {}
|
||||
pub fn static_method() {}
|
||||
pub const CONST: u8 = 0;
|
||||
// pub type AssocTy = u8;
|
||||
}
|
||||
|
||||
pub macro mac() {
|
||||
let value = <Pub>::method;
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
value;
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
let value = Pub::method;
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
value;
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
let value = <Pub>::static_method;
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
value;
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
let value = Pub::static_method;
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
value;
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
Pub(Priv).method();
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
|
||||
<Pub>::CONST;
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
Pub::CONST;
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
|
||||
// let _: Pub::AssocTy;
|
||||
// pub type InSignatureTy = Pub::AssocTy;
|
||||
}
|
||||
}
|
||||
fn priv_parent_substs() {
|
||||
priv_parent_substs::mac!();
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
151
src/test/compile-fail/privacy/associated-item-privacy-trait.rs
Normal file
151
src/test/compile-fail/privacy/associated-item-privacy-trait.rs
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
// 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.
|
||||
|
||||
// ignore-tidy-linelength
|
||||
|
||||
#![feature(decl_macro, associated_type_defaults)]
|
||||
#![allow(unused, private_in_public)]
|
||||
|
||||
mod priv_trait {
|
||||
trait PrivTr {
|
||||
fn method(&self) {}
|
||||
const CONST: u8 = 0;
|
||||
type AssocTy = u8;
|
||||
}
|
||||
pub struct Pub;
|
||||
impl PrivTr for Pub {}
|
||||
pub trait PubTr: PrivTr {}
|
||||
|
||||
pub macro mac() {
|
||||
let value = <Pub as PrivTr>::method;
|
||||
//~^ ERROR type `for<'r> fn(&'r priv_trait::Pub) {<priv_trait::Pub as priv_trait::PrivTr>::method}` is private
|
||||
value;
|
||||
//~^ ERROR type `for<'r> fn(&'r priv_trait::Pub) {<priv_trait::Pub as priv_trait::PrivTr>::method}` is private
|
||||
Pub.method();
|
||||
//~^ ERROR type `for<'r> fn(&'r Self) {<Self as priv_trait::PrivTr>::method}` is private
|
||||
<Pub as PrivTr>::CONST;
|
||||
//~^ ERROR associated constant `PrivTr::CONST` is private
|
||||
let _: <Pub as PrivTr>::AssocTy;
|
||||
//~^ ERROR trait `priv_trait::PrivTr` is private
|
||||
//~| ERROR trait `priv_trait::PrivTr` is private
|
||||
pub type InSignatureTy = <Pub as PrivTr>::AssocTy;
|
||||
//~^ ERROR trait `priv_trait::PrivTr` is private
|
||||
pub trait InSignatureTr: PrivTr {}
|
||||
//~^ ERROR trait `priv_trait::PrivTr` is private
|
||||
impl PrivTr for u8 {}
|
||||
//~^ ERROR trait `priv_trait::PrivTr` is private
|
||||
}
|
||||
}
|
||||
fn priv_trait() {
|
||||
priv_trait::mac!();
|
||||
}
|
||||
|
||||
mod priv_signature {
|
||||
pub trait PubTr {
|
||||
fn method(&self, arg: Priv) {}
|
||||
}
|
||||
struct Priv;
|
||||
pub struct Pub;
|
||||
impl PubTr for Pub {}
|
||||
|
||||
pub macro mac() {
|
||||
let value = <Pub as PubTr>::method;
|
||||
//~^ ERROR type `priv_signature::Priv` is private
|
||||
value;
|
||||
//~^ ERROR type `priv_signature::Priv` is private
|
||||
Pub.method(loop {});
|
||||
//~^ ERROR type `priv_signature::Priv` is private
|
||||
}
|
||||
}
|
||||
fn priv_signature() {
|
||||
priv_signature::mac!();
|
||||
}
|
||||
|
||||
mod priv_substs {
|
||||
pub trait PubTr {
|
||||
fn method<T>(&self) {}
|
||||
}
|
||||
struct Priv;
|
||||
pub struct Pub;
|
||||
impl PubTr for Pub {}
|
||||
|
||||
pub macro mac() {
|
||||
let value = <Pub as PubTr>::method::<Priv>;
|
||||
//~^ ERROR type `priv_substs::Priv` is private
|
||||
value;
|
||||
//~^ ERROR type `priv_substs::Priv` is private
|
||||
Pub.method::<Priv>();
|
||||
//~^ ERROR type `priv_substs::Priv` is private
|
||||
}
|
||||
}
|
||||
fn priv_substs() {
|
||||
priv_substs::mac!();
|
||||
}
|
||||
|
||||
mod priv_parent_substs {
|
||||
pub trait PubTr<T = Priv> {
|
||||
fn method(&self) {}
|
||||
const CONST: u8 = 0;
|
||||
type AssocTy = u8;
|
||||
}
|
||||
struct Priv;
|
||||
pub struct Pub;
|
||||
impl PubTr<Priv> for Pub {}
|
||||
impl PubTr<Pub> for Priv {}
|
||||
|
||||
pub macro mac() {
|
||||
let value = <Pub as PubTr>::method;
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
value;
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
let value = <Pub as PubTr<_>>::method;
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
value;
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
Pub.method();
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
|
||||
let value = <Priv as PubTr<_>>::method;
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
value;
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
Priv.method();
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
|
||||
<Pub as PubTr>::CONST;
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
<Pub as PubTr<_>>::CONST;
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
<Priv as PubTr<_>>::CONST;
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
|
||||
let _: <Pub as PubTr>::AssocTy;
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
//~| ERROR type `priv_parent_substs::Priv` is private
|
||||
let _: <Pub as PubTr<_>>::AssocTy;
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
//~| ERROR type `priv_parent_substs::Priv` is private
|
||||
let _: <Priv as PubTr<_>>::AssocTy;
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
//~| ERROR type `priv_parent_substs::Priv` is private
|
||||
|
||||
pub type InSignatureTy1 = <Pub as PubTr>::AssocTy;
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
pub type InSignatureTy2 = <Priv as PubTr<Pub>>::AssocTy;
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
impl PubTr for u8 {}
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
}
|
||||
}
|
||||
fn priv_parent_substs() {
|
||||
priv_parent_substs::mac!();
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
// 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, associated_type_defaults)]
|
||||
#![allow(unused, private_in_public)]
|
||||
|
||||
mod priv_trait {
|
||||
trait PrivTr {
|
||||
type AssocTy = u8;
|
||||
}
|
||||
pub trait PubTr: PrivTr {}
|
||||
|
||||
pub macro mac1() {
|
||||
let _: Box<PubTr<AssocTy = u8>>;
|
||||
//~^ ERROR type `priv_trait::PubTr<AssocTy=u8> + '<empty>` is private
|
||||
//~| ERROR type `priv_trait::PubTr<AssocTy=u8> + '<empty>` is private
|
||||
type InSignatureTy2 = Box<PubTr<AssocTy = u8>>;
|
||||
//~^ ERROR type `priv_trait::PubTr<AssocTy=u8> + 'static` is private
|
||||
trait InSignatureTr2: PubTr<AssocTy = u8> {}
|
||||
//~^ ERROR trait `priv_trait::PrivTr` is private
|
||||
}
|
||||
pub macro mac2() {
|
||||
let _: Box<PrivTr<AssocTy = u8>>;
|
||||
//~^ ERROR type `priv_trait::PrivTr<AssocTy=u8> + '<empty>` is private
|
||||
//~| ERROR type `priv_trait::PrivTr<AssocTy=u8> + '<empty>` is private
|
||||
type InSignatureTy1 = Box<PrivTr<AssocTy = u8>>;
|
||||
//~^ ERROR type `priv_trait::PrivTr<AssocTy=u8> + 'static` is private
|
||||
trait InSignatureTr1: PrivTr<AssocTy = u8> {}
|
||||
//~^ ERROR trait `priv_trait::PrivTr` is private
|
||||
}
|
||||
}
|
||||
fn priv_trait1() {
|
||||
priv_trait::mac1!();
|
||||
}
|
||||
fn priv_trait2() {
|
||||
priv_trait::mac2!();
|
||||
}
|
||||
|
||||
mod priv_parent_substs {
|
||||
pub trait PubTrWithParam<T = Priv> {
|
||||
type AssocTy = u8;
|
||||
}
|
||||
struct Priv;
|
||||
pub trait PubTr: PubTrWithParam<Priv> {}
|
||||
|
||||
pub macro mac() {
|
||||
let _: Box<PubTrWithParam<AssocTy = u8>>;
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
//~| ERROR type `priv_parent_substs::Priv` is private
|
||||
let _: Box<PubTr<AssocTy = u8>>;
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
//~| ERROR type `priv_parent_substs::Priv` is private
|
||||
pub type InSignatureTy1 = Box<PubTrWithParam<AssocTy = u8>>;
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
pub type InSignatureTy2 = Box<PubTr<AssocTy = u8>>;
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
trait InSignatureTr1: PubTrWithParam<AssocTy = u8> {}
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
trait InSignatureTr2: PubTr<AssocTy = u8> {}
|
||||
//~^ ERROR type `priv_parent_substs::Priv` is private
|
||||
}
|
||||
}
|
||||
fn priv_parent_substs() {
|
||||
priv_parent_substs::mac!();
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
43
src/test/compile-fail/private-in-public-assoc-ty.rs
Normal file
43
src/test/compile-fail/private-in-public-assoc-ty.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Private types and traits are not allowed in interfaces of associated types.
|
||||
// This test also ensures that the checks are performed even inside private modules.
|
||||
|
||||
#![feature(associated_type_defaults)]
|
||||
|
||||
mod m {
|
||||
struct Priv;
|
||||
trait PrivTr {}
|
||||
impl PrivTr for Priv {}
|
||||
pub trait PubTrAux1<T> {}
|
||||
pub trait PubTrAux2 { type A; }
|
||||
|
||||
// "Private-in-public in associated types is hard error" in RFC 2145
|
||||
// applies only to the aliased types, not bounds.
|
||||
pub trait PubTr {
|
||||
//~^ WARN private trait `m::PrivTr` in public interface
|
||||
//~| WARN this was previously accepted
|
||||
//~| WARN private type `m::Priv` in public interface
|
||||
//~| WARN this was previously accepted
|
||||
type Alias1: PrivTr;
|
||||
type Alias2: PubTrAux1<Priv> = u8;
|
||||
type Alias3: PubTrAux2<A = Priv> = u8;
|
||||
|
||||
type Alias4 = Priv;
|
||||
//~^ ERROR private type `m::Priv` in public interface
|
||||
}
|
||||
impl PubTr for u8 {
|
||||
type Alias1 = Priv;
|
||||
//~^ ERROR private type `m::Priv` in public interface
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
45
src/test/compile-fail/private-in-public-ill-formed.rs
Normal file
45
src/test/compile-fail/private-in-public-ill-formed.rs
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
mod aliases_pub {
|
||||
struct Priv;
|
||||
mod m {
|
||||
pub struct Pub3;
|
||||
}
|
||||
|
||||
trait PrivTr {
|
||||
type AssocAlias;
|
||||
}
|
||||
impl PrivTr for Priv {
|
||||
type AssocAlias = m::Pub3;
|
||||
}
|
||||
|
||||
impl (<Priv as PrivTr>::AssocAlias) { //~ ERROR no base type found for inherent implementation
|
||||
pub fn f(arg: Priv) {} // private type `aliases_pub::Priv` in public interface
|
||||
}
|
||||
}
|
||||
|
||||
mod aliases_priv {
|
||||
struct Priv;
|
||||
struct Priv3;
|
||||
|
||||
trait PrivTr {
|
||||
type AssocAlias;
|
||||
}
|
||||
impl PrivTr for Priv {
|
||||
type AssocAlias = Priv3;
|
||||
}
|
||||
|
||||
impl (<Priv as PrivTr>::AssocAlias) { //~ ERROR no base type found for inherent implementation
|
||||
pub fn f(arg: Priv) {} // OK
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
#![feature(associated_type_defaults)]
|
||||
#![deny(private_in_public)]
|
||||
#![allow(unused)]
|
||||
#![allow(improper_ctypes)]
|
||||
|
||||
mod types {
|
||||
|
|
@ -35,7 +34,6 @@ mod types {
|
|||
const C: Priv = Priv; //~ ERROR private type `types::Priv` in public interface
|
||||
//~^ WARNING hard error
|
||||
type Alias = Priv; //~ ERROR private type `types::Priv` in public interface
|
||||
//~^ WARNING hard error
|
||||
fn f1(arg: Priv) {} //~ ERROR private type `types::Priv` in public interface
|
||||
//~^ WARNING hard error
|
||||
fn f2() -> Priv { panic!() } //~ ERROR private type `types::Priv` in public interface
|
||||
|
|
@ -51,7 +49,6 @@ mod types {
|
|||
}
|
||||
impl PubTr for Pub {
|
||||
type Alias = Priv; //~ ERROR private type `types::Priv` in public interface
|
||||
//~^ WARNING hard error
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -146,7 +143,6 @@ mod impls {
|
|||
}
|
||||
impl PubTr for Pub {
|
||||
type Alias = Priv; //~ ERROR private type `impls::Priv` in public interface
|
||||
//~^ WARNING hard error
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -220,21 +216,14 @@ mod aliases_pub {
|
|||
pub fn f(arg: Priv) {} //~ ERROR private type `aliases_pub::Priv` in public interface
|
||||
//~^ WARNING hard error
|
||||
}
|
||||
// This doesn't even parse
|
||||
// impl <Priv as PrivTr>::AssocAlias {
|
||||
// pub fn f(arg: Priv) {} // ERROR private type `aliases_pub::Priv` in public interface
|
||||
// }
|
||||
impl PrivUseAliasTr for PrivUseAlias {
|
||||
type Check = Priv; //~ ERROR private type `aliases_pub::Priv` in public interface
|
||||
//~^ WARNING hard error
|
||||
}
|
||||
impl PrivUseAliasTr for PrivAlias {
|
||||
type Check = Priv; //~ ERROR private type `aliases_pub::Priv` in public interface
|
||||
//~^ WARNING hard error
|
||||
}
|
||||
impl PrivUseAliasTr for <Priv as PrivTr>::AssocAlias {
|
||||
type Check = Priv; //~ ERROR private type `aliases_pub::Priv` in public interface
|
||||
//~^ WARNING hard error
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -273,10 +262,6 @@ mod aliases_priv {
|
|||
impl PrivAlias {
|
||||
pub fn f(arg: Priv) {} // OK
|
||||
}
|
||||
// This doesn't even parse
|
||||
// impl <Priv as PrivTr>::AssocAlias {
|
||||
// pub fn f(arg: Priv) {} // OK
|
||||
// }
|
||||
impl PrivUseAliasTr for PrivUseAlias {
|
||||
type Check = Priv; // OK
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
// aux-build:private-inferred-type.rs
|
||||
|
||||
// error-pattern:type `fn() {ext::priv_fn}` is private
|
||||
// error-pattern:static `PRIV_STATIC` 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
|
||||
|
|
|
|||
|
|
@ -11,10 +11,11 @@
|
|||
#![feature(associated_consts)]
|
||||
#![feature(conservative_impl_trait)]
|
||||
#![feature(decl_macro)]
|
||||
#![allow(warnings)]
|
||||
#![allow(private_in_public)]
|
||||
|
||||
mod m {
|
||||
fn priv_fn() {}
|
||||
static PRIV_STATIC: u8 = 0;
|
||||
enum PrivEnum { Variant }
|
||||
pub enum PubEnum { Variant }
|
||||
trait PrivTrait { fn method() {} }
|
||||
|
|
@ -47,6 +48,7 @@ mod m {
|
|||
|
||||
pub macro m() {
|
||||
priv_fn; //~ ERROR type `fn() {m::priv_fn}` is private
|
||||
PRIV_STATIC; // OK, not cross-crate
|
||||
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
|
||||
|
|
@ -68,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 }
|
||||
|
|
@ -88,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 {
|
||||
|
|
|
|||
|
|
@ -131,6 +131,16 @@ fn check_assoc_ty<T: assoc_ty::C>() {
|
|||
let _: T::A; //~ ERROR associated type `A` is private
|
||||
let _: T::B; // OK
|
||||
let _: T::C; // OK
|
||||
|
||||
// Associated types, bindings
|
||||
let _: assoc_ty::B<
|
||||
B = u8, // OK
|
||||
>;
|
||||
let _: C<
|
||||
A = u8, //~ ERROR associated type `A` is private
|
||||
B = u8, // OK
|
||||
C = u8, // OK
|
||||
>;
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue