Skip to content

Commit c5842b0

Browse files
committedNov 8, 2022
Auto merge of #103965 - petrochenkov:effvisperf3, r=oli-obk
resolve: More detailed effective visibility tracking for imports Per-`DefId` tracking is not enough, due to glob imports in particular, which have a single `DefId` for the whole glob import item. We need to track this stuff per every introduced name (`NameBinding`). Also drop `extern` blocks from the effective visibility table, they are nominally private and it doesn't make sense to keep them there. Later commits add some debug-only invariant checking and optimiaztions to mitigate regressions in #103965 (comment). This is a bugfix and continuation of #102026.
2 parents ddfe1e8 + 43bea6c commit c5842b0

File tree

8 files changed

+339
-133
lines changed

8 files changed

+339
-133
lines changed
 

‎compiler/rustc_middle/src/middle/privacy.rs

+103-21
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
//! A pass that checks to make sure private fields and methods aren't used
22
//! outside their scopes. This pass will also generate a set of exported items
33
//! which are available for use externally when compiled as a library.
4-
use crate::ty::{DefIdTree, Visibility};
4+
use crate::ty::{DefIdTree, TyCtxt, Visibility};
55
use rustc_data_structures::fx::FxHashMap;
66
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
7+
use rustc_hir::def::DefKind;
78
use rustc_macros::HashStable;
89
use rustc_query_system::ich::StableHashingContext;
910
use rustc_span::def_id::LocalDefId;
11+
use std::hash::Hash;
1012

1113
/// Represents the levels of effective visibility an item can have.
1214
///
@@ -74,9 +76,9 @@ impl EffectiveVisibility {
7476
}
7577

7678
/// Holds a map of effective visibilities for reachable HIR nodes.
77-
#[derive(Default, Clone, Debug)]
78-
pub struct EffectiveVisibilities {
79-
map: FxHashMap<LocalDefId, EffectiveVisibility>,
79+
#[derive(Clone, Debug)]
80+
pub struct EffectiveVisibilities<Id = LocalDefId> {
81+
map: FxHashMap<Id, EffectiveVisibility>,
8082
}
8183

8284
impl EffectiveVisibilities {
@@ -111,12 +113,30 @@ impl EffectiveVisibilities {
111113
})
112114
}
113115

114-
pub fn effective_vis(&self, id: LocalDefId) -> Option<&EffectiveVisibility> {
115-
self.map.get(&id)
116-
}
117-
118-
pub fn iter(&self) -> impl Iterator<Item = (&LocalDefId, &EffectiveVisibility)> {
119-
self.map.iter()
116+
// FIXME: Share code with `fn update`.
117+
pub fn update_eff_vis(
118+
&mut self,
119+
def_id: LocalDefId,
120+
eff_vis: &EffectiveVisibility,
121+
tree: impl DefIdTree,
122+
) {
123+
use std::collections::hash_map::Entry;
124+
match self.map.entry(def_id) {
125+
Entry::Occupied(mut occupied) => {
126+
let old_eff_vis = occupied.get_mut();
127+
for l in Level::all_levels() {
128+
let vis_at_level = eff_vis.at_level(l);
129+
let old_vis_at_level = old_eff_vis.at_level_mut(l);
130+
if vis_at_level != old_vis_at_level
131+
&& vis_at_level.is_at_least(*old_vis_at_level, tree)
132+
{
133+
*old_vis_at_level = *vis_at_level
134+
}
135+
}
136+
old_eff_vis
137+
}
138+
Entry::Vacant(vacant) => vacant.insert(*eff_vis),
139+
};
120140
}
121141

122142
pub fn set_public_at_level(
@@ -137,26 +157,82 @@ impl EffectiveVisibilities {
137157
self.map.insert(id, effective_vis);
138158
}
139159

160+
pub fn check_invariants(&self, tcx: TyCtxt<'_>, early: bool) {
161+
if !cfg!(debug_assertions) {
162+
return;
163+
}
164+
for (&def_id, ev) in &self.map {
165+
// More direct visibility levels can never go farther than less direct ones,
166+
// neither of effective visibilities can go farther than nominal visibility,
167+
// and all effective visibilities are larger or equal than private visibility.
168+
let private_vis = Visibility::Restricted(tcx.parent_module_from_def_id(def_id));
169+
let span = tcx.def_span(def_id.to_def_id());
170+
if !ev.direct.is_at_least(private_vis, tcx) {
171+
span_bug!(span, "private {:?} > direct {:?}", private_vis, ev.direct);
172+
}
173+
if !ev.reexported.is_at_least(ev.direct, tcx) {
174+
span_bug!(span, "direct {:?} > reexported {:?}", ev.direct, ev.reexported);
175+
}
176+
if !ev.reachable.is_at_least(ev.reexported, tcx) {
177+
span_bug!(span, "reexported {:?} > reachable {:?}", ev.reexported, ev.reachable);
178+
}
179+
if !ev.reachable_through_impl_trait.is_at_least(ev.reachable, tcx) {
180+
span_bug!(
181+
span,
182+
"reachable {:?} > reachable_through_impl_trait {:?}",
183+
ev.reachable,
184+
ev.reachable_through_impl_trait
185+
);
186+
}
187+
let nominal_vis = tcx.visibility(def_id);
188+
let def_kind = tcx.opt_def_kind(def_id);
189+
// FIXME: `rustc_privacy` is not yet updated for the new logic and can set
190+
// effective visibilities that are larger than the nominal one.
191+
if !nominal_vis.is_at_least(ev.reachable_through_impl_trait, tcx) && early {
192+
span_bug!(
193+
span,
194+
"{:?}: reachable_through_impl_trait {:?} > nominal {:?}",
195+
def_id,
196+
ev.reachable_through_impl_trait,
197+
nominal_vis
198+
);
199+
}
200+
// Fully private items are never put into the table, this is important for performance.
201+
// FIXME: Fully private `mod` items are currently put into the table.
202+
if ev.reachable_through_impl_trait == private_vis && def_kind != Some(DefKind::Mod) {
203+
span_bug!(span, "fully private item in the table {:?}: {:?}", def_id, ev.direct);
204+
}
205+
}
206+
}
207+
}
208+
209+
impl<Id: Eq + Hash> EffectiveVisibilities<Id> {
210+
pub fn iter(&self) -> impl Iterator<Item = (&Id, &EffectiveVisibility)> {
211+
self.map.iter()
212+
}
213+
214+
pub fn effective_vis(&self, id: Id) -> Option<&EffectiveVisibility> {
215+
self.map.get(&id)
216+
}
217+
140218
// `parent_id` is not necessarily a parent in source code tree,
141219
// it is the node from which the maximum effective visibility is inherited.
142220
pub fn update(
143221
&mut self,
144-
id: LocalDefId,
222+
id: Id,
145223
nominal_vis: Visibility,
146-
default_vis: impl FnOnce() -> Visibility,
147-
parent_id: LocalDefId,
224+
default_vis: Visibility,
225+
inherited_eff_vis: Option<EffectiveVisibility>,
148226
level: Level,
149227
tree: impl DefIdTree,
150228
) -> bool {
151229
let mut changed = false;
152-
let mut current_effective_vis = self.effective_vis(id).copied().unwrap_or_else(|| {
153-
if id.is_top_level_module() {
154-
EffectiveVisibility::from_vis(Visibility::Public)
155-
} else {
156-
EffectiveVisibility::from_vis(default_vis())
157-
}
158-
});
159-
if let Some(inherited_effective_vis) = self.effective_vis(parent_id) {
230+
let mut current_effective_vis = self
231+
.map
232+
.get(&id)
233+
.copied()
234+
.unwrap_or_else(|| EffectiveVisibility::from_vis(default_vis));
235+
if let Some(inherited_effective_vis) = inherited_eff_vis {
160236
let mut inherited_effective_vis_at_prev_level =
161237
*inherited_effective_vis.at_level(level);
162238
let mut calculated_effective_vis = inherited_effective_vis_at_prev_level;
@@ -194,6 +270,12 @@ impl EffectiveVisibilities {
194270
}
195271
}
196272

273+
impl<Id> Default for EffectiveVisibilities<Id> {
274+
fn default() -> Self {
275+
EffectiveVisibilities { map: Default::default() }
276+
}
277+
}
278+
197279
impl<'a> HashStable<StableHashingContext<'a>> for EffectiveVisibilities {
198280
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
199281
let EffectiveVisibilities { ref map } = *self;

‎compiler/rustc_privacy/src/lib.rs

+10
Original file line numberDiff line numberDiff line change
@@ -959,13 +959,21 @@ impl<'tcx, 'a> Visitor<'tcx> for TestReachabilityVisitor<'tcx, 'a> {
959959
for variant in def.variants.iter() {
960960
let variant_id = self.tcx.hir().local_def_id(variant.id);
961961
self.effective_visibility_diagnostic(variant_id);
962+
if let Some(ctor_hir_id) = variant.data.ctor_hir_id() {
963+
let ctor_def_id = self.tcx.hir().local_def_id(ctor_hir_id);
964+
self.effective_visibility_diagnostic(ctor_def_id);
965+
}
962966
for field in variant.data.fields() {
963967
let def_id = self.tcx.hir().local_def_id(field.hir_id);
964968
self.effective_visibility_diagnostic(def_id);
965969
}
966970
}
967971
}
968972
hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => {
973+
if let Some(ctor_hir_id) = def.ctor_hir_id() {
974+
let ctor_def_id = self.tcx.hir().local_def_id(ctor_hir_id);
975+
self.effective_visibility_diagnostic(ctor_def_id);
976+
}
969977
for field in def.fields() {
970978
let def_id = self.tcx.hir().local_def_id(field.hir_id);
971979
self.effective_visibility_diagnostic(def_id);
@@ -2131,6 +2139,7 @@ fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities {
21312139
changed: false,
21322140
};
21332141

2142+
visitor.effective_visibilities.check_invariants(tcx, true);
21342143
loop {
21352144
tcx.hir().walk_toplevel_module(&mut visitor);
21362145
if visitor.changed {
@@ -2139,6 +2148,7 @@ fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities {
21392148
break;
21402149
}
21412150
}
2151+
visitor.effective_visibilities.check_invariants(tcx, false);
21422152

21432153
let mut check_visitor =
21442154
TestReachabilityVisitor { tcx, effective_visibilities: &visitor.effective_visibilities };

‎compiler/rustc_resolve/src/effective_visibilities.rs

+131-91
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,38 @@
1-
use crate::{ImportKind, NameBindingKind, Resolver};
1+
use crate::{ImportKind, NameBinding, NameBindingKind, Resolver, ResolverTree};
22
use rustc_ast::ast;
33
use rustc_ast::visit;
44
use rustc_ast::visit::Visitor;
55
use rustc_ast::Crate;
66
use rustc_ast::EnumDef;
7+
use rustc_data_structures::intern::Interned;
78
use rustc_hir::def_id::LocalDefId;
89
use rustc_hir::def_id::CRATE_DEF_ID;
9-
use rustc_middle::middle::privacy::Level;
10-
use rustc_middle::ty::{DefIdTree, Visibility};
10+
use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, Level};
11+
use rustc_middle::ty::Visibility;
12+
13+
type ImportId<'a> = Interned<'a, NameBinding<'a>>;
14+
15+
#[derive(Clone, Copy)]
16+
enum ParentId<'a> {
17+
Def(LocalDefId),
18+
Import(ImportId<'a>),
19+
}
20+
21+
impl ParentId<'_> {
22+
fn level(self) -> Level {
23+
match self {
24+
ParentId::Def(_) => Level::Direct,
25+
ParentId::Import(_) => Level::Reexported,
26+
}
27+
}
28+
}
1129

1230
pub struct EffectiveVisibilitiesVisitor<'r, 'a> {
1331
r: &'r mut Resolver<'a>,
32+
/// While walking import chains we need to track effective visibilities per-binding, and def id
33+
/// keys in `Resolver::effective_visibilities` are not enough for that, because multiple
34+
/// bindings can correspond to a single def id in imports. So we keep a separate table.
35+
import_effective_visibilities: EffectiveVisibilities<ImportId<'a>>,
1436
changed: bool,
1537
}
1638

@@ -19,21 +41,57 @@ impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> {
1941
/// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we
2042
/// need access to a TyCtxt for that.
2143
pub fn compute_effective_visibilities<'c>(r: &'r mut Resolver<'a>, krate: &'c Crate) {
22-
let mut visitor = EffectiveVisibilitiesVisitor { r, changed: false };
44+
let mut visitor = EffectiveVisibilitiesVisitor {
45+
r,
46+
import_effective_visibilities: Default::default(),
47+
changed: false,
48+
};
2349

24-
visitor.update(CRATE_DEF_ID, Visibility::Public, CRATE_DEF_ID, Level::Direct);
50+
visitor.update(CRATE_DEF_ID, CRATE_DEF_ID);
2551
visitor.set_bindings_effective_visibilities(CRATE_DEF_ID);
2652

2753
while visitor.changed {
28-
visitor.reset();
54+
visitor.changed = false;
2955
visit::walk_crate(&mut visitor, krate);
3056
}
3157

58+
// Update visibilities for import def ids. These are not used during the
59+
// `EffectiveVisibilitiesVisitor` pass, because we have more detailed binding-based
60+
// information, but are used by later passes. Effective visibility of an import def id
61+
// is the maximum value among visibilities of bindings corresponding to that def id.
62+
for (binding, eff_vis) in visitor.import_effective_visibilities.iter() {
63+
let NameBindingKind::Import { import, .. } = binding.kind else { unreachable!() };
64+
if let Some(node_id) = import.id() {
65+
let mut update = |node_id| {
66+
r.effective_visibilities.update_eff_vis(
67+
r.local_def_id(node_id),
68+
eff_vis,
69+
ResolverTree(&r.definitions, &r.crate_loader),
70+
)
71+
};
72+
update(node_id);
73+
if let ImportKind::Single { additional_ids: (id1, id2), .. } = import.kind {
74+
// In theory all the single import IDs have individual visibilities and
75+
// effective visibilities, but in practice these IDs go straigth to HIR
76+
// where all their few uses assume that their (effective) visibility
77+
// applies to the whole syntactic `use` item. So they all get the same
78+
// value which is the maximum of all bindings. Maybe HIR for imports
79+
// shouldn't use three IDs at all.
80+
if id1 != ast::DUMMY_NODE_ID {
81+
update(id1);
82+
}
83+
if id2 != ast::DUMMY_NODE_ID {
84+
update(id2);
85+
}
86+
}
87+
}
88+
}
89+
3290
info!("resolve::effective_visibilities: {:#?}", r.effective_visibilities);
3391
}
3492

35-
fn reset(&mut self) {
36-
self.changed = false;
93+
fn nearest_normal_mod(&mut self, def_id: LocalDefId) -> LocalDefId {
94+
self.r.get_nearest_non_block_module(def_id.to_def_id()).nearest_parent_mod().expect_local()
3795
}
3896

3997
/// Update effective visibilities of bindings in the given module,
@@ -48,92 +106,83 @@ impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> {
48106
// Set the given effective visibility level to `Level::Direct` and
49107
// sets the rest of the `use` chain to `Level::Reexported` until
50108
// we hit the actual exported item.
109+
let mut parent_id = ParentId::Def(module_id);
110+
while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind {
111+
let binding_id = ImportId::new_unchecked(binding);
112+
self.update_import(binding_id, parent_id);
51113

52-
// FIXME: tag and is_public() condition should be removed, but assertions occur.
53-
let tag = if binding.is_import() { Level::Reexported } else { Level::Direct };
54-
if binding.vis.is_public() {
55-
let mut prev_parent_id = module_id;
56-
let mut level = Level::Direct;
57-
while let NameBindingKind::Import { binding: nested_binding, import, .. } =
58-
binding.kind
59-
{
60-
let mut update = |node_id| {
61-
self.update(
62-
self.r.local_def_id(node_id),
63-
binding.vis.expect_local(),
64-
prev_parent_id,
65-
level,
66-
)
67-
};
68-
match import.kind {
69-
ImportKind::Single { id, additional_ids, .. } => {
70-
// In theory all the import IDs have individual visibilities and
71-
// effective visibilities, but in practice these IDs go straigth to
72-
// HIR where all their few uses assume that their (effective)
73-
// visibility applies to the whole syntactic `use` item. So we
74-
// update them all to the maximum value among the potential
75-
// individual effective visibilities. Maybe HIR for imports
76-
// shouldn't use three IDs at all.
77-
update(id);
78-
update(additional_ids.0);
79-
update(additional_ids.1);
80-
prev_parent_id = self.r.local_def_id(id);
81-
}
82-
ImportKind::Glob { id, .. } | ImportKind::ExternCrate { id, .. } => {
83-
update(id);
84-
prev_parent_id = self.r.local_def_id(id);
85-
}
86-
ImportKind::MacroUse => {
87-
// In theory we should reset the parent id to something private
88-
// here, but `macro_use` imports always refer to external items,
89-
// so it doesn't matter and we can just do nothing.
90-
}
91-
ImportKind::MacroExport => {
92-
// In theory we should reset the parent id to something public
93-
// here, but it has the same effect as leaving the previous parent,
94-
// so we can just do nothing.
95-
}
96-
}
97-
98-
level = Level::Reexported;
99-
binding = nested_binding;
100-
}
114+
parent_id = ParentId::Import(binding_id);
115+
binding = nested_binding;
101116
}
102117

103118
if let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) {
104-
self.update(def_id, binding.vis.expect_local(), module_id, tag);
119+
self.update_def(def_id, binding.vis.expect_local(), parent_id);
105120
}
106121
}
107122
}
108123
}
109124

110-
fn update(
111-
&mut self,
112-
def_id: LocalDefId,
125+
fn effective_vis(&self, parent_id: ParentId<'a>) -> Option<EffectiveVisibility> {
126+
match parent_id {
127+
ParentId::Def(def_id) => self.r.effective_visibilities.effective_vis(def_id),
128+
ParentId::Import(binding) => self.import_effective_visibilities.effective_vis(binding),
129+
}
130+
.copied()
131+
}
132+
133+
/// The update is guaranteed to not change the table and we can skip it.
134+
fn is_noop_update(
135+
&self,
136+
parent_id: ParentId<'a>,
113137
nominal_vis: Visibility,
114-
parent_id: LocalDefId,
115-
tag: Level,
116-
) {
117-
let module_id = self
118-
.r
119-
.get_nearest_non_block_module(def_id.to_def_id())
120-
.nearest_parent_mod()
121-
.expect_local();
122-
if nominal_vis == Visibility::Restricted(module_id)
123-
|| self.r.visibilities[&parent_id] == Visibility::Restricted(module_id)
124-
{
138+
default_vis: Visibility,
139+
) -> bool {
140+
nominal_vis == default_vis
141+
|| match parent_id {
142+
ParentId::Def(def_id) => self.r.visibilities[&def_id],
143+
ParentId::Import(binding) => binding.vis.expect_local(),
144+
} == default_vis
145+
}
146+
147+
fn update_import(&mut self, binding: ImportId<'a>, parent_id: ParentId<'a>) {
148+
let NameBindingKind::Import { import, .. } = binding.kind else { unreachable!() };
149+
let nominal_vis = binding.vis.expect_local();
150+
let default_vis = Visibility::Restricted(
151+
import
152+
.id()
153+
.map(|id| self.nearest_normal_mod(self.r.local_def_id(id)))
154+
.unwrap_or(CRATE_DEF_ID),
155+
);
156+
if self.is_noop_update(parent_id, nominal_vis, default_vis) {
125157
return;
126158
}
127-
let mut effective_visibilities = std::mem::take(&mut self.r.effective_visibilities);
128-
self.changed |= effective_visibilities.update(
159+
self.changed |= self.import_effective_visibilities.update(
160+
binding,
161+
nominal_vis,
162+
default_vis,
163+
self.effective_vis(parent_id),
164+
parent_id.level(),
165+
ResolverTree(&self.r.definitions, &self.r.crate_loader),
166+
);
167+
}
168+
169+
fn update_def(&mut self, def_id: LocalDefId, nominal_vis: Visibility, parent_id: ParentId<'a>) {
170+
let default_vis = Visibility::Restricted(self.nearest_normal_mod(def_id));
171+
if self.is_noop_update(parent_id, nominal_vis, default_vis) {
172+
return;
173+
}
174+
self.changed |= self.r.effective_visibilities.update(
129175
def_id,
130176
nominal_vis,
131-
|| Visibility::Restricted(module_id),
132-
parent_id,
133-
tag,
134-
&*self.r,
177+
if def_id == CRATE_DEF_ID { Visibility::Public } else { default_vis },
178+
self.effective_vis(parent_id),
179+
parent_id.level(),
180+
ResolverTree(&self.r.definitions, &self.r.crate_loader),
135181
);
136-
self.r.effective_visibilities = effective_visibilities;
182+
}
183+
184+
fn update(&mut self, def_id: LocalDefId, parent_id: LocalDefId) {
185+
self.update_def(def_id, self.r.visibilities[&def_id], ParentId::Def(parent_id));
137186
}
138187
}
139188

@@ -151,12 +200,6 @@ impl<'r, 'ast> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r> {
151200
"ast::ItemKind::MacCall encountered, this should not anymore appear at this stage"
152201
),
153202

154-
// Foreign modules inherit level from parents.
155-
ast::ItemKind::ForeignMod(..) => {
156-
let parent_id = self.r.local_parent(def_id);
157-
self.update(def_id, Visibility::Public, parent_id, Level::Direct);
158-
}
159-
160203
ast::ItemKind::Mod(..) => {
161204
self.set_bindings_effective_visibilities(def_id);
162205
visit::walk_item(self, item);
@@ -167,18 +210,14 @@ impl<'r, 'ast> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r> {
167210
for variant in variants {
168211
let variant_def_id = self.r.local_def_id(variant.id);
169212
for field in variant.data.fields() {
170-
let field_def_id = self.r.local_def_id(field.id);
171-
let vis = self.r.visibilities[&field_def_id];
172-
self.update(field_def_id, vis, variant_def_id, Level::Direct);
213+
self.update(self.r.local_def_id(field.id), variant_def_id);
173214
}
174215
}
175216
}
176217

177218
ast::ItemKind::Struct(ref def, _) | ast::ItemKind::Union(ref def, _) => {
178219
for field in def.fields() {
179-
let field_def_id = self.r.local_def_id(field.id);
180-
let vis = self.r.visibilities[&field_def_id];
181-
self.update(field_def_id, vis, def_id, Level::Direct);
220+
self.update(self.r.local_def_id(field.id), def_id);
182221
}
183222
}
184223

@@ -194,6 +233,7 @@ impl<'r, 'ast> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r> {
194233
| ast::ItemKind::TyAlias(..)
195234
| ast::ItemKind::TraitAlias(..)
196235
| ast::ItemKind::MacroDef(..)
236+
| ast::ItemKind::ForeignMod(..)
197237
| ast::ItemKind::Fn(..) => return,
198238
}
199239
}

‎compiler/rustc_resolve/src/lib.rs

+16-3
Original file line numberDiff line numberDiff line change
@@ -1106,17 +1106,30 @@ impl<'a> AsMut<Resolver<'a>> for Resolver<'a> {
11061106
}
11071107
}
11081108

1109-
impl<'a, 'b> DefIdTree for &'a Resolver<'b> {
1109+
/// A minimal subset of resolver that can implemenent `DefIdTree`, sometimes
1110+
/// required to satisfy borrow checker by avoiding borrowing the whole resolver.
1111+
#[derive(Clone, Copy)]
1112+
struct ResolverTree<'a, 'b>(&'a Definitions, &'a CrateLoader<'b>);
1113+
1114+
impl DefIdTree for ResolverTree<'_, '_> {
11101115
#[inline]
11111116
fn opt_parent(self, id: DefId) -> Option<DefId> {
1117+
let ResolverTree(definitions, crate_loader) = self;
11121118
match id.as_local() {
1113-
Some(id) => self.definitions.def_key(id).parent,
1114-
None => self.cstore().def_key(id).parent,
1119+
Some(id) => definitions.def_key(id).parent,
1120+
None => crate_loader.cstore().def_key(id).parent,
11151121
}
11161122
.map(|index| DefId { index, ..id })
11171123
}
11181124
}
11191125

1126+
impl<'a, 'b> DefIdTree for &'a Resolver<'b> {
1127+
#[inline]
1128+
fn opt_parent(self, id: DefId) -> Option<DefId> {
1129+
ResolverTree(&self.definitions, &self.crate_loader).opt_parent(id)
1130+
}
1131+
}
1132+
11201133
impl Resolver<'_> {
11211134
fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
11221135
self.node_id_to_def_id.get(&node).copied()

‎src/test/ui/privacy/effective_visibilities.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ mod outer { //~ ERROR Direct: pub(crate), Reexported: pub(crate), Reachable: pub
66
pub mod inner1 { //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
77

88
#[rustc_effective_visibility]
9-
extern "C" {} //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
9+
extern "C" {} //~ ERROR not in the table
1010

1111
#[rustc_effective_visibility]
1212
pub trait PubTrait { //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
@@ -18,6 +18,7 @@ mod outer { //~ ERROR Direct: pub(crate), Reexported: pub(crate), Reachable: pub
1818

1919
#[rustc_effective_visibility]
2020
struct PrivStruct; //~ ERROR not in the table
21+
//~| ERROR not in the table
2122

2223
#[rustc_effective_visibility]
2324
pub union PubUnion { //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
@@ -31,6 +32,7 @@ mod outer { //~ ERROR Direct: pub(crate), Reexported: pub(crate), Reachable: pub
3132
pub enum Enum { //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
3233
#[rustc_effective_visibility]
3334
A( //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
35+
//~| ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
3436
#[rustc_effective_visibility]
3537
PubUnion, //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
3638
),

‎src/test/ui/privacy/effective_visibilities.stderr

+29-17
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImpl
1010
LL | pub mod inner1 {
1111
| ^^^^^^^^^^^^^^
1212

13-
error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
13+
error: not in the table
1414
--> $DIR/effective_visibilities.rs:9:9
1515
|
1616
LL | extern "C" {}
@@ -28,92 +28,104 @@ error: not in the table
2828
LL | struct PrivStruct;
2929
| ^^^^^^^^^^^^^^^^^
3030

31+
error: not in the table
32+
--> $DIR/effective_visibilities.rs:20:9
33+
|
34+
LL | struct PrivStruct;
35+
| ^^^^^^^^^^^^^^^^^
36+
3137
error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
32-
--> $DIR/effective_visibilities.rs:23:9
38+
--> $DIR/effective_visibilities.rs:24:9
3339
|
3440
LL | pub union PubUnion {
3541
| ^^^^^^^^^^^^^^^^^^
3642

3743
error: not in the table
38-
--> $DIR/effective_visibilities.rs:25:13
44+
--> $DIR/effective_visibilities.rs:26:13
3945
|
4046
LL | a: u8,
4147
| ^^^^^
4248

4349
error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
44-
--> $DIR/effective_visibilities.rs:27:13
50+
--> $DIR/effective_visibilities.rs:28:13
4551
|
4652
LL | pub b: u8,
4753
| ^^^^^^^^^
4854

4955
error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
50-
--> $DIR/effective_visibilities.rs:31:9
56+
--> $DIR/effective_visibilities.rs:32:9
5157
|
5258
LL | pub enum Enum {
5359
| ^^^^^^^^^^^^^
5460

5561
error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
56-
--> $DIR/effective_visibilities.rs:33:13
62+
--> $DIR/effective_visibilities.rs:34:13
63+
|
64+
LL | A(
65+
| ^
66+
67+
error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
68+
--> $DIR/effective_visibilities.rs:34:13
5769
|
5870
LL | A(
5971
| ^
6072

6173
error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
62-
--> $DIR/effective_visibilities.rs:35:17
74+
--> $DIR/effective_visibilities.rs:37:17
6375
|
6476
LL | PubUnion,
6577
| ^^^^^^^^
6678

6779
error: not in the table
68-
--> $DIR/effective_visibilities.rs:41:5
80+
--> $DIR/effective_visibilities.rs:43:5
6981
|
7082
LL | macro_rules! none_macro {
7183
| ^^^^^^^^^^^^^^^^^^^^^^^
7284

7385
error: Direct: pub(self), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
74-
--> $DIR/effective_visibilities.rs:47:5
86+
--> $DIR/effective_visibilities.rs:49:5
7587
|
7688
LL | macro_rules! public_macro {
7789
| ^^^^^^^^^^^^^^^^^^^^^^^^^
7890

7991
error: Direct: pub(crate), Reexported: pub(crate), Reachable: pub, ReachableThroughImplTrait: pub
80-
--> $DIR/effective_visibilities.rs:52:5
92+
--> $DIR/effective_visibilities.rs:54:5
8193
|
8294
LL | pub struct ReachableStruct {
8395
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
8496

8597
error: Direct: pub(crate), Reexported: pub(crate), Reachable: pub, ReachableThroughImplTrait: pub
86-
--> $DIR/effective_visibilities.rs:54:9
98+
--> $DIR/effective_visibilities.rs:56:9
8799
|
88100
LL | pub a: u8,
89101
| ^^^^^^^^^
90102

91103
error: Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
92-
--> $DIR/effective_visibilities.rs:59:9
104+
--> $DIR/effective_visibilities.rs:61:9
93105
|
94106
LL | pub use outer::inner1;
95107
| ^^^^^^^^^^^^^
96108

97109
error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
98-
--> $DIR/effective_visibilities.rs:65:5
110+
--> $DIR/effective_visibilities.rs:67:5
99111
|
100112
LL | pub type HalfPublicImport = u8;
101113
| ^^^^^^^^^^^^^^^^^^^^^^^^^
102114

103115
error: Direct: pub(crate), Reexported: pub(crate), Reachable: pub(crate), ReachableThroughImplTrait: pub(crate)
104-
--> $DIR/effective_visibilities.rs:68:5
116+
--> $DIR/effective_visibilities.rs:70:5
105117
|
106118
LL | pub(crate) const HalfPublicImport: u8 = 0;
107119
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
108120

109121
error: Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
110-
--> $DIR/effective_visibilities.rs:72:9
122+
--> $DIR/effective_visibilities.rs:74:9
111123
|
112124
LL | pub use half_public_import::HalfPublicImport;
113125
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
114126

115127
error: Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
116-
--> $DIR/effective_visibilities.rs:72:9
128+
--> $DIR/effective_visibilities.rs:74:9
117129
|
118130
LL | pub use half_public_import::HalfPublicImport;
119131
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -130,5 +142,5 @@ error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImpl
130142
LL | type B;
131143
| ^^^^^^
132144

133-
error: aborting due to 22 previous errors
145+
error: aborting due to 24 previous errors
134146

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Effective visibility tracking for imports is fine-grained, so `S2` is not fully exported
2+
// even if its parent import (`m::*`) is fully exported as a `use` item.
3+
4+
#![feature(rustc_attrs)]
5+
6+
mod m {
7+
#[rustc_effective_visibility]
8+
pub struct S1 {} //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
9+
#[rustc_effective_visibility]
10+
pub struct S2 {} //~ ERROR Direct: pub(crate), Reexported: pub(crate), Reachable: pub(crate), ReachableThroughImplTrait: pub(crate)
11+
}
12+
13+
mod glob {
14+
#[rustc_effective_visibility]
15+
pub use crate::m::*; //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
16+
}
17+
18+
#[rustc_effective_visibility]
19+
pub use glob::S1; //~ ERROR Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
20+
21+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
2+
--> $DIR/effective_visibilities_glob.rs:8:5
3+
|
4+
LL | pub struct S1 {}
5+
| ^^^^^^^^^^^^^
6+
7+
error: Direct: pub(crate), Reexported: pub(crate), Reachable: pub(crate), ReachableThroughImplTrait: pub(crate)
8+
--> $DIR/effective_visibilities_glob.rs:10:5
9+
|
10+
LL | pub struct S2 {}
11+
| ^^^^^^^^^^^^^
12+
13+
error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
14+
--> $DIR/effective_visibilities_glob.rs:15:13
15+
|
16+
LL | pub use crate::m::*;
17+
| ^^^^^^^^
18+
19+
error: Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
20+
--> $DIR/effective_visibilities_glob.rs:19:9
21+
|
22+
LL | pub use glob::S1;
23+
| ^^^^^^^^
24+
25+
error: aborting due to 4 previous errors
26+

0 commit comments

Comments
 (0)
Please sign in to comment.