Skip to content

Commit a12706c

Browse files
committed
Auto merge of #46083 - petrochenkov:morepriv, r=nikomatsakis
Type privacy polishing Various preparations before implementing rust-lang/rfcs#2145 containing final minor breaking changes (mostly for unstable code or code using `allow(private_in_public)`). (Continuation of #42125, #44633 and #41332.) It would be good to run crater on this. r? @eddyb
2 parents fdfb007 + c6209a3 commit a12706c

18 files changed

+656
-136
lines changed

src/librustc/hir/mod.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -258,8 +258,13 @@ impl Path {
258258

259259
impl fmt::Debug for Path {
260260
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
261-
write!(f, "path({})",
262-
print::to_string(print::NO_ANN, |s| s.print_path(self, false)))
261+
write!(f, "path({})", print::to_string(print::NO_ANN, |s| s.print_path(self, false)))
262+
}
263+
}
264+
265+
impl fmt::Display for Path {
266+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
267+
write!(f, "{}", print::to_string(print::NO_ANN, |s| s.print_path(self, false)))
263268
}
264269
}
265270

src/librustc_privacy/lib.rs

+78-37
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,7 @@ struct TypePrivacyVisitor<'a, 'tcx: 'a> {
614614
tcx: TyCtxt<'a, 'tcx, 'tcx>,
615615
tables: &'a ty::TypeckTables<'tcx>,
616616
current_item: DefId,
617+
in_body: bool,
617618
span: Span,
618619
empty_tables: &'a ty::TypeckTables<'tcx>,
619620
}
@@ -671,10 +672,8 @@ impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> {
671672
// Take node ID of an expression or pattern and check its type for privacy.
672673
fn check_expr_pat_type(&mut self, id: hir::HirId, span: Span) -> bool {
673674
self.span = span;
674-
if let Some(ty) = self.tables.node_id_to_type_opt(id) {
675-
if ty.visit_with(self) {
676-
return true;
677-
}
675+
if self.tables.node_id_to_type(id).visit_with(self) {
676+
return true;
678677
}
679678
if self.tables.node_substs(id).visit_with(self) {
680679
return true;
@@ -688,6 +687,16 @@ impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> {
688687
}
689688
false
690689
}
690+
691+
fn check_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>) -> bool {
692+
if !self.item_is_accessible(trait_ref.def_id) {
693+
let msg = format!("trait `{}` is private", trait_ref);
694+
self.tcx.sess.span_err(self.span, &msg);
695+
return true;
696+
}
697+
698+
trait_ref.super_visit_with(self)
699+
}
691700
}
692701

693702
impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
@@ -699,16 +708,18 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
699708

700709
fn visit_nested_body(&mut self, body: hir::BodyId) {
701710
let orig_tables = replace(&mut self.tables, self.tcx.body_tables(body));
711+
let orig_in_body = replace(&mut self.in_body, true);
702712
let body = self.tcx.hir.body(body);
703713
self.visit_body(body);
704714
self.tables = orig_tables;
715+
self.in_body = orig_in_body;
705716
}
706717

707718
fn visit_ty(&mut self, hir_ty: &'tcx hir::Ty) {
708719
self.span = hir_ty.span;
709-
if let Some(ty) = self.tables.node_id_to_type_opt(hir_ty.hir_id) {
720+
if self.in_body {
710721
// Types in bodies.
711-
if ty.visit_with(self) {
722+
if self.tables.node_id_to_type(hir_ty.hir_id).visit_with(self) {
712723
return;
713724
}
714725
} else {
@@ -724,10 +735,21 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
724735
}
725736

726737
fn visit_trait_ref(&mut self, trait_ref: &'tcx hir::TraitRef) {
727-
if !self.item_is_accessible(trait_ref.path.def.def_id()) {
728-
let msg = format!("trait `{:?}` is private", trait_ref.path);
729-
self.tcx.sess.span_err(self.span, &msg);
730-
return;
738+
self.span = trait_ref.path.span;
739+
if !self.in_body {
740+
// Avoid calling `hir_trait_to_predicates` in bodies, it will ICE.
741+
// The traits' privacy in bodies is already checked as a part of trait object types.
742+
let (principal, projections) =
743+
rustc_typeck::hir_trait_to_predicates(self.tcx, trait_ref);
744+
if self.check_trait_ref(*principal.skip_binder()) {
745+
return;
746+
}
747+
for poly_predicate in projections {
748+
let tcx = self.tcx;
749+
if self.check_trait_ref(poly_predicate.skip_binder().projection_ty.trait_ref(tcx)) {
750+
return;
751+
}
752+
}
731753
}
732754

733755
intravisit::walk_trait_ref(self, trait_ref);
@@ -760,19 +782,35 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
760782
intravisit::walk_expr(self, expr);
761783
}
762784

785+
// Prohibit access to associated items with insufficient nominal visibility.
786+
//
787+
// Additionally, until better reachability analysis for macros 2.0 is available,
788+
// we prohibit access to private statics from other crates, this allows to give
789+
// more code internal visibility at link time. (Access to private functions
790+
// is already prohibited by type privacy for funciton types.)
763791
fn visit_qpath(&mut self, qpath: &'tcx hir::QPath, id: ast::NodeId, span: Span) {
764-
// Inherent associated constants don't have self type in substs,
765-
// we have to check it additionally.
766-
if let hir::QPath::TypeRelative(..) = *qpath {
767-
let hir_id = self.tcx.hir.node_to_hir_id(id);
768-
if let Some(def) = self.tables.type_dependent_defs().get(hir_id).cloned() {
769-
if let Some(assoc_item) = self.tcx.opt_associated_item(def.def_id()) {
770-
if let ty::ImplContainer(impl_def_id) = assoc_item.container {
771-
if self.tcx.type_of(impl_def_id).visit_with(self) {
772-
return;
773-
}
774-
}
775-
}
792+
let def = match *qpath {
793+
hir::QPath::Resolved(_, ref path) => match path.def {
794+
Def::Method(..) | Def::AssociatedConst(..) |
795+
Def::AssociatedTy(..) | Def::Static(..) => Some(path.def),
796+
_ => None,
797+
}
798+
hir::QPath::TypeRelative(..) => {
799+
let hir_id = self.tcx.hir.node_to_hir_id(id);
800+
self.tables.type_dependent_defs().get(hir_id).cloned()
801+
}
802+
};
803+
if let Some(def) = def {
804+
let def_id = def.def_id();
805+
let is_local_static = if let Def::Static(..) = def { def_id.is_local() } else { false };
806+
if !self.item_is_accessible(def_id) && !is_local_static {
807+
let name = match *qpath {
808+
hir::QPath::Resolved(_, ref path) => format!("{}", path),
809+
hir::QPath::TypeRelative(_, ref segment) => segment.name.to_string(),
810+
};
811+
let msg = format!("{} `{}` is private", def.kind_name(), name);
812+
self.tcx.sess.span_err(span, &msg);
813+
return;
776814
}
777815
}
778816

@@ -807,9 +845,11 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
807845
item.id,
808846
&mut self.tables,
809847
self.empty_tables);
848+
let orig_in_body = replace(&mut self.in_body, false);
810849
self.current_item = self.tcx.hir.local_def_id(item.id);
811850
intravisit::walk_item(self, item);
812851
self.tables = orig_tables;
852+
self.in_body = orig_in_body;
813853
self.current_item = orig_current_item;
814854
}
815855

@@ -869,13 +909,8 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
869909
}
870910
}
871911
ty::TyProjection(ref proj) => {
872-
let trait_ref = proj.trait_ref(self.tcx);
873-
if !self.item_is_accessible(trait_ref.def_id) {
874-
let msg = format!("trait `{}` is private", trait_ref);
875-
self.tcx.sess.span_err(self.span, &msg);
876-
return true;
877-
}
878-
if trait_ref.super_visit_with(self) {
912+
let tcx = self.tcx;
913+
if self.check_trait_ref(proj.trait_ref(tcx)) {
879914
return true;
880915
}
881916
}
@@ -1278,6 +1313,7 @@ struct SearchInterfaceForPrivateItemsVisitor<'a, 'tcx: 'a> {
12781313
min_visibility: ty::Visibility,
12791314
has_pub_restricted: bool,
12801315
has_old_errors: bool,
1316+
in_assoc_ty: bool,
12811317
}
12821318

12831319
impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
@@ -1338,11 +1374,11 @@ impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
13381374
self.min_visibility = vis;
13391375
}
13401376
if !vis.is_at_least(self.required_visibility, self.tcx) {
1341-
if self.has_pub_restricted || self.has_old_errors {
1377+
if self.has_pub_restricted || self.has_old_errors || self.in_assoc_ty {
13421378
struct_span_err!(self.tcx.sess, self.span, E0445,
13431379
"private trait `{}` in public interface", trait_ref)
13441380
.span_label(self.span, format!(
1345-
"private trait can't be public"))
1381+
"can't leak private trait"))
13461382
.emit();
13471383
} else {
13481384
self.tcx.lint_node(lint::builtin::PRIVATE_IN_PUBLIC,
@@ -1393,7 +1429,7 @@ impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'
13931429
self.min_visibility = vis;
13941430
}
13951431
if !vis.is_at_least(self.required_visibility, self.tcx) {
1396-
if self.has_pub_restricted || self.has_old_errors {
1432+
if self.has_pub_restricted || self.has_old_errors || self.in_assoc_ty {
13971433
let mut err = struct_span_err!(self.tcx.sess, self.span, E0446,
13981434
"private type `{}` in public interface", ty);
13991435
err.span_label(self.span, "can't leak private type");
@@ -1454,6 +1490,7 @@ impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
14541490
required_visibility,
14551491
has_pub_restricted: self.has_pub_restricted,
14561492
has_old_errors,
1493+
in_assoc_ty: false,
14571494
}
14581495
}
14591496
}
@@ -1494,6 +1531,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
14941531

14951532
for trait_item_ref in trait_item_refs {
14961533
let mut check = self.check(trait_item_ref.id.node_id, item_visibility);
1534+
check.in_assoc_ty = trait_item_ref.kind == hir::AssociatedItemKind::Type;
14971535
check.generics().predicates();
14981536

14991537
if trait_item_ref.kind == hir::AssociatedItemKind::Type &&
@@ -1544,10 +1582,10 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
15441582

15451583
for impl_item_ref in impl_item_refs {
15461584
let impl_item = self.tcx.hir.impl_item(impl_item_ref.id);
1547-
let impl_item_vis =
1548-
ty::Visibility::from_hir(&impl_item.vis, item.id, tcx);
1549-
self.check(impl_item.id, min(impl_item_vis, ty_vis))
1550-
.generics().predicates().ty();
1585+
let impl_item_vis = ty::Visibility::from_hir(&impl_item.vis, item.id, tcx);
1586+
let mut check = self.check(impl_item.id, min(impl_item_vis, ty_vis));
1587+
check.in_assoc_ty = impl_item_ref.kind == hir::AssociatedItemKind::Type;
1588+
check.generics().predicates().ty();
15511589

15521590
// Recurse for e.g. `impl Trait` (see `visit_ty`).
15531591
self.inner_visibility = impl_item_vis;
@@ -1562,7 +1600,9 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
15621600
self.check(item.id, vis).generics().predicates();
15631601
for impl_item_ref in impl_item_refs {
15641602
let impl_item = self.tcx.hir.impl_item(impl_item_ref.id);
1565-
self.check(impl_item.id, vis).generics().predicates().ty();
1603+
let mut check = self.check(impl_item.id, vis);
1604+
check.in_assoc_ty = impl_item_ref.kind == hir::AssociatedItemKind::Type;
1605+
check.generics().predicates().ty();
15661606

15671607
// Recurse for e.g. `impl Trait` (see `visit_ty`).
15681608
self.inner_visibility = vis;
@@ -1629,6 +1669,7 @@ fn privacy_access_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
16291669
tcx,
16301670
tables: &empty_tables,
16311671
current_item: DefId::local(CRATE_DEF_INDEX),
1672+
in_body: false,
16321673
span: krate.span,
16331674
empty_tables: &empty_tables,
16341675
};

0 commit comments

Comments
 (0)