Skip to content

Commit d39dddf

Browse files
committed
Auto merge of #57344 - petrochenkov:regreach, r=arielb1
privacy: Fix regression in impl reachability Rollback to pre-#56878 logic of determining reachability. `reachability(impl Trait<Substs> for Type<Substs>) = reachability(Trait & Type)`, substs are ignored. Fixes #57264
2 parents b92552d + fb00313 commit d39dddf

File tree

5 files changed

+78
-11
lines changed

5 files changed

+78
-11
lines changed

src/librustc_privacy/lib.rs

+41-11
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ mod diagnostics;
5151
/// in `impl Trait`, see individual commits in `DefIdVisitorSkeleton::visit_ty`.
5252
trait DefIdVisitor<'a, 'tcx: 'a> {
5353
fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx>;
54-
fn recurse_into_assoc_tys(&self) -> bool { true }
54+
fn shallow(&self) -> bool { false }
55+
fn skip_assoc_tys(&self) -> bool { false }
5556
fn visit_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool;
5657

5758
/// Not overridden, but used to actually visit types and traits.
@@ -86,7 +87,8 @@ impl<'a, 'tcx, V> DefIdVisitorSkeleton<'_, 'a, 'tcx, V>
8687
{
8788
fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> bool {
8889
let TraitRef { def_id, substs } = trait_ref;
89-
self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref) || substs.visit_with(self)
90+
self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref) ||
91+
(!self.def_id_visitor.shallow() && substs.visit_with(self))
9092
}
9193

9294
fn visit_predicates(&mut self, predicates: Lrc<ty::GenericPredicates<'tcx>>) -> bool {
@@ -138,6 +140,9 @@ impl<'a, 'tcx, V> TypeVisitor<'tcx> for DefIdVisitorSkeleton<'_, 'a, 'tcx, V>
138140
if self.def_id_visitor.visit_def_id(def_id, "type", ty) {
139141
return true;
140142
}
143+
if self.def_id_visitor.shallow() {
144+
return false;
145+
}
141146
// Default type visitor doesn't visit signatures of fn types.
142147
// Something like `fn() -> Priv {my_func}` is considered a private type even if
143148
// `my_func` is public, so we need to visit signatures.
@@ -159,18 +164,20 @@ impl<'a, 'tcx, V> TypeVisitor<'tcx> for DefIdVisitorSkeleton<'_, 'a, 'tcx, V>
159164
}
160165
}
161166
ty::Projection(proj) | ty::UnnormalizedProjection(proj) => {
162-
if !self.def_id_visitor.recurse_into_assoc_tys() {
167+
if self.def_id_visitor.skip_assoc_tys() {
163168
// Visitors searching for minimal visibility/reachability want to
164169
// conservatively approximate associated types like `<Type as Trait>::Alias`
165170
// as visible/reachable even if both `Type` and `Trait` are private.
166171
// Ideally, associated types should be substituted in the same way as
167172
// free type aliases, but this isn't done yet.
168173
return false;
169174
}
170-
// This will also visit substs, so we don't need to recurse.
175+
// This will also visit substs if necessary, so we don't need to recurse.
171176
return self.visit_trait(proj.trait_ref(tcx));
172177
}
173178
ty::Dynamic(predicates, ..) => {
179+
// All traits in the list are considered the "primary" part of the type
180+
// and are visited by shallow visitors.
174181
for predicate in *predicates.skip_binder() {
175182
let trait_ref = match *predicate {
176183
ty::ExistentialPredicate::Trait(trait_ref) => trait_ref,
@@ -187,9 +194,13 @@ impl<'a, 'tcx, V> TypeVisitor<'tcx> for DefIdVisitorSkeleton<'_, 'a, 'tcx, V>
187194
ty::Opaque(def_id, ..) => {
188195
// Skip repeated `Opaque`s to avoid infinite recursion.
189196
if self.visited_opaque_tys.insert(def_id) {
190-
// Default type visitor doesn't visit traits in `impl Trait`.
191-
// Something like `impl PrivTr` is considered a private type,
192-
// so we need to visit the traits additionally.
197+
// The intent is to treat `impl Trait1 + Trait2` identically to
198+
// `dyn Trait1 + Trait2`. Therefore we ignore def-id of the opaque type itself
199+
// (it either has no visibility, or its visibility is insignificant, like
200+
// visibilities of type aliases) and recurse into predicates instead to go
201+
// through the trait list (default type visitor doesn't visit those traits).
202+
// All traits in the list are considered the "primary" part of the type
203+
// and are visited by shallow visitors.
193204
if self.visit_predicates(tcx.predicates_of(def_id)) {
194205
return true;
195206
}
@@ -206,7 +217,7 @@ impl<'a, 'tcx, V> TypeVisitor<'tcx> for DefIdVisitorSkeleton<'_, 'a, 'tcx, V>
206217
bug!("unexpected type: {:?}", ty),
207218
}
208219

209-
ty.super_visit_with(self)
220+
!self.def_id_visitor.shallow() && ty.super_visit_with(self)
210221
}
211222
}
212223

@@ -325,7 +336,8 @@ struct FindMin<'a, 'tcx, VL: VisibilityLike> {
325336

326337
impl<'a, 'tcx, VL: VisibilityLike> DefIdVisitor<'a, 'tcx> for FindMin<'a, 'tcx, VL> {
327338
fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { self.tcx }
328-
fn recurse_into_assoc_tys(&self) -> bool { false }
339+
fn shallow(&self) -> bool { VL::SHALLOW }
340+
fn skip_assoc_tys(&self) -> bool { true }
329341
fn visit_def_id(&mut self, def_id: DefId, _kind: &str, _descr: &dyn fmt::Display) -> bool {
330342
self.min = VL::new_min(self, def_id);
331343
false
@@ -334,9 +346,10 @@ impl<'a, 'tcx, VL: VisibilityLike> DefIdVisitor<'a, 'tcx> for FindMin<'a, 'tcx,
334346

335347
trait VisibilityLike: Sized {
336348
const MAX: Self;
349+
const SHALLOW: bool = false;
337350
fn new_min<'a, 'tcx>(find: &FindMin<'a, 'tcx, Self>, def_id: DefId) -> Self;
338351

339-
// Returns an over-approximation (`recurse_into_assoc_tys` = false) of visibility due to
352+
// Returns an over-approximation (`skip_assoc_tys` = true) of visibility due to
340353
// associated types for which we can't determine visibility precisely.
341354
fn of_impl<'a, 'tcx>(node_id: ast::NodeId, tcx: TyCtxt<'a, 'tcx, 'tcx>,
342355
access_levels: &'a AccessLevels) -> Self {
@@ -357,6 +370,16 @@ impl VisibilityLike for ty::Visibility {
357370
}
358371
impl VisibilityLike for Option<AccessLevel> {
359372
const MAX: Self = Some(AccessLevel::Public);
373+
// Type inference is very smart sometimes.
374+
// It can make an impl reachable even some components of its type or trait are unreachable.
375+
// E.g. methods of `impl ReachableTrait<UnreachableTy> for ReachableTy<UnreachableTy> { ... }`
376+
// can be usable from other crates (#57264). So we skip substs when calculating reachability
377+
// and consider an impl reachable if its "shallow" type and trait are reachable.
378+
//
379+
// The assumption we make here is that type-inference won't let you use an impl without knowing
380+
// both "shallow" version of its self type and "shallow" version of its trait if it exists
381+
// (which require reaching the `DefId`s in them).
382+
const SHALLOW: bool = true;
360383
fn new_min<'a, 'tcx>(find: &FindMin<'a, 'tcx, Self>, def_id: DefId) -> Self {
361384
cmp::min(if let Some(node_id) = find.tcx.hir().as_local_node_id(def_id) {
362385
find.access_levels.map.get(&node_id).cloned()
@@ -542,7 +565,7 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
542565
// Visit everything except for private impl items.
543566
hir::ItemKind::Impl(.., ref impl_item_refs) => {
544567
if item_level.is_some() {
545-
self.reach(item.id, item_level).generics().predicates();
568+
self.reach(item.id, item_level).generics().predicates().ty().trait_ref();
546569

547570
for impl_item_ref in impl_item_refs {
548571
let impl_item_level = self.get(impl_item_ref.id.node_id);
@@ -701,6 +724,13 @@ impl<'a, 'tcx> ReachEverythingInTheInterfaceVisitor<'_, 'a, 'tcx> {
701724
self.visit(self.ev.tcx.type_of(self.item_def_id));
702725
self
703726
}
727+
728+
fn trait_ref(&mut self) -> &mut Self {
729+
if let Some(trait_ref) = self.ev.tcx.impl_trait_ref(self.item_def_id) {
730+
self.visit_trait(trait_ref);
731+
}
732+
self
733+
}
704734
}
705735

706736
impl<'a, 'tcx> DefIdVisitor<'a, 'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'a, 'tcx> {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
mod inner {
2+
pub struct PubUnnameable;
3+
}
4+
5+
pub struct Pub<T>(T);
6+
7+
impl Pub<inner::PubUnnameable> {
8+
pub fn pub_method() {}
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
mod inner {
2+
pub struct PubUnnameable;
3+
4+
impl PubUnnameable {
5+
pub fn pub_method(self) {}
6+
}
7+
}
8+
9+
pub trait PubTraitWithSingleImplementor {}
10+
impl PubTraitWithSingleImplementor for Option<inner::PubUnnameable> {}

src/test/ui/privacy/issue-57264-1.rs

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// compile-pass
2+
// aux-build:issue-57264-1.rs
3+
4+
extern crate issue_57264_1;
5+
6+
fn main() {
7+
issue_57264_1::Pub::pub_method();
8+
}

src/test/ui/privacy/issue-57264-2.rs

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// compile-pass
2+
// aux-build:issue-57264-2.rs
3+
4+
extern crate issue_57264_2;
5+
6+
fn infer<T: issue_57264_2::PubTraitWithSingleImplementor>(arg: T) -> T { arg }
7+
8+
fn main() {
9+
infer(None).unwrap().pub_method();
10+
}

0 commit comments

Comments
 (0)