Skip to content

Commit 4f56ffe

Browse files
committed
Fix order-dependent visibility diagnostics
1 parent 03c609a commit 4f56ffe

11 files changed

Lines changed: 163 additions & 94 deletions

compiler/rustc_resolve/src/build_reduced_graph.rs

Lines changed: 66 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,10 @@ use crate::imports::{ImportData, ImportKind, OnUnknownData};
3535
use crate::macros::{MacroRulesDecl, MacroRulesScope, MacroRulesScopeRef};
3636
use crate::ref_mut::CmCell;
3737
use crate::{
38-
BindingKey, Decl, DeclData, DeclKind, ExternModule, ExternPreludeEntry, Finalize, IdentKey,
39-
LocalModule, MacroData, Module, ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, Res,
40-
Resolver, Segment, Used, VisResolutionError, errors,
38+
BindingKey, Decl, DeclData, DeclKind, DelayedVisResolutionError, ExternModule,
39+
ExternPreludeEntry, Finalize, IdentKey, LocalModule, MacroData, Module, ModuleKind,
40+
ModuleOrUniformRoot, ParentScope, PathResult, Res, Resolver, Segment, Used, VisResolutionError,
41+
errors,
4142
};
4243

4344
impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
@@ -355,38 +356,50 @@ impl<'ra, 'tcx> AsMut<Resolver<'ra, 'tcx>> for DefCollector<'_, 'ra, 'tcx> {
355356
}
356357
}
357358

358-
impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> {
359-
fn res(&self, def_id: impl Into<DefId>) -> Res {
360-
let def_id = def_id.into();
361-
Res::Def(self.r.tcx.def_kind(def_id), def_id)
362-
}
359+
impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
360+
fn visibility_path_segments(
361+
&self,
362+
path: &ast::Path,
363+
) -> Result<Vec<Segment>, VisResolutionError> {
364+
let ident = path.segments.get(0).expect("empty path in visibility").ident;
365+
let crate_root = if ident.is_path_segment_keyword() {
366+
None
367+
} else if ident.span.is_rust_2015() {
368+
Some(Segment::from_ident(Ident::new(
369+
kw::PathRoot,
370+
path.span.shrink_to_lo().with_ctxt(ident.span.ctxt()),
371+
)))
372+
} else {
373+
return Err(VisResolutionError::Relative2018(ident.span, path.clone()));
374+
};
363375

364-
fn resolve_visibility(&mut self, vis: &ast::Visibility) -> Visibility {
365-
self.try_resolve_visibility(vis, true).unwrap_or_else(|err| {
366-
self.r.report_vis_error(err);
367-
Visibility::Public
368-
})
376+
Ok(crate_root
377+
.into_iter()
378+
.chain(path.segments.iter().map(|seg| seg.into()))
379+
.collect::<Vec<_>>())
369380
}
370381

371-
fn try_resolve_visibility<'ast>(
382+
pub(crate) fn try_resolve_visibility(
372383
&mut self,
373-
vis: &'ast ast::Visibility,
384+
parent_scope: ParentScope<'ra>,
385+
vis: &ast::Visibility,
374386
finalize: bool,
375-
) -> Result<Visibility, VisResolutionError<'ast>> {
376-
let parent_scope = &self.parent_scope;
387+
record_partial_res: bool,
388+
) -> Result<Visibility, VisResolutionError> {
389+
let parent_scope_ref = &parent_scope;
377390
match vis.kind {
378391
ast::VisibilityKind::Public => Ok(Visibility::Public),
379392
ast::VisibilityKind::Inherited => {
380-
Ok(match self.parent_scope.module.kind {
393+
Ok(match parent_scope.module.kind {
381394
// Any inherited visibility resolved directly inside an enum or trait
382395
// (i.e. variants, fields, and trait items) inherits from the visibility
383396
// of the enum or trait.
384397
ModuleKind::Def(DefKind::Enum | DefKind::Trait, def_id, _) => {
385-
self.r.tcx.visibility(def_id).expect_local()
398+
self.tcx.visibility(def_id).expect_local()
386399
}
387400
// Otherwise, the visibility is restricted to the nearest parent `mod` item.
388401
_ => Visibility::Restricted(
389-
self.parent_scope.module.nearest_parent_mod().expect_local(),
402+
parent_scope.module.nearest_parent_mod().expect_local(),
390403
),
391404
})
392405
}
@@ -395,48 +408,33 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> {
395408
// paths" right now, so on 2018 edition we only allow module-relative paths for now.
396409
// On 2015 edition visibilities are resolved as crate-relative by default,
397410
// so we are prepending a root segment if necessary.
398-
let ident = path.segments.get(0).expect("empty path in visibility").ident;
399-
let crate_root = if ident.is_path_segment_keyword() {
400-
None
401-
} else if ident.span.is_rust_2015() {
402-
Some(Segment::from_ident(Ident::new(
403-
kw::PathRoot,
404-
path.span.shrink_to_lo().with_ctxt(ident.span.ctxt()),
405-
)))
406-
} else {
407-
return Err(VisResolutionError::Relative2018(ident.span, path));
408-
};
409-
410-
let segments = crate_root
411-
.into_iter()
412-
.chain(path.segments.iter().map(|seg| seg.into()))
413-
.collect::<Vec<_>>();
411+
let segments = self.visibility_path_segments(path)?;
414412
let expected_found_error = |res| {
415413
Err(VisResolutionError::ExpectedFound(
416414
path.span,
417415
Segment::names_to_string(&segments),
418416
res,
419417
))
420418
};
421-
match self.r.cm().resolve_path(
419+
match self.cm().resolve_path(
422420
&segments,
423421
None,
424-
parent_scope,
422+
parent_scope_ref,
425423
finalize.then(|| Finalize::new(id, path.span)),
426424
None,
427425
None,
428426
) {
429427
PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
430428
let res = module.res().expect("visibility resolved to unnamed block");
431-
if finalize {
432-
self.r.record_partial_res(id, PartialRes::new(res));
429+
if record_partial_res {
430+
self.record_partial_res(id, PartialRes::new(res));
433431
}
434432
if module.is_normal() {
435433
match res {
436434
Res::Err => Ok(Visibility::Public),
437435
_ => {
438436
let vis = Visibility::Restricted(res.def_id());
439-
if self.r.is_accessible_from(vis, parent_scope.module) {
437+
if self.is_accessible_from(vis, parent_scope.module) {
440438
Ok(vis.expect_local())
441439
} else {
442440
Err(VisResolutionError::AncestorOnly(path.span))
@@ -465,6 +463,27 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> {
465463
}
466464
}
467465
}
466+
}
467+
468+
impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> {
469+
fn res(&self, def_id: impl Into<DefId>) -> Res {
470+
let def_id = def_id.into();
471+
Res::Def(self.r.tcx.def_kind(def_id), def_id)
472+
}
473+
474+
fn resolve_visibility(&mut self, vis: &ast::Visibility) -> Visibility {
475+
match self.r.try_resolve_visibility(self.parent_scope, vis, true, true) {
476+
Ok(vis) => vis,
477+
Err(error) => {
478+
self.r.delayed_vis_resolution_errors.push(DelayedVisResolutionError {
479+
vis: vis.clone(),
480+
parent_scope: self.parent_scope,
481+
error,
482+
});
483+
Visibility::Public
484+
}
485+
}
486+
}
468487

469488
fn insert_field_idents(&mut self, def_id: LocalDefId, fields: &[ast::FieldDef]) {
470489
if fields.iter().any(|field| field.is_placeholder) {
@@ -904,7 +923,8 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> {
904923
// correct visibilities for unnamed field placeholders specifically, so the
905924
// constructor visibility should still be determined correctly.
906925
let field_vis = self
907-
.try_resolve_visibility(&field.vis, false)
926+
.r
927+
.try_resolve_visibility(self.parent_scope, &field.vis, false, false)
908928
.unwrap_or(Visibility::Public);
909929
if ctor_vis.greater_than(field_vis, self.r.tcx) {
910930
ctor_vis = field_vis;
@@ -1339,9 +1359,10 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> {
13391359
let vis = match item.kind {
13401360
// Visibilities must not be resolved non-speculatively twice
13411361
// and we already resolved this one as a `fn` item visibility.
1342-
ItemKind::Fn(..) => {
1343-
self.try_resolve_visibility(&item.vis, false).unwrap_or(Visibility::Public)
1344-
}
1362+
ItemKind::Fn(..) => self
1363+
.r
1364+
.try_resolve_visibility(self.parent_scope, &item.vis, false, false)
1365+
.unwrap_or(Visibility::Public),
13451366
_ => self.resolve_visibility(&item.vis),
13461367
};
13471368
if !vis.is_public() {

compiler/rustc_resolve/src/diagnostics.rs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,10 @@ use crate::imports::{Import, ImportKind};
4848
use crate::late::{DiagMetadata, PatternSource, Rib};
4949
use crate::{
5050
AmbiguityError, AmbiguityKind, AmbiguityWarning, BindingError, BindingKey, Decl, DeclKind,
51-
Finalize, ForwardGenericParamBanReason, HasGenericParams, IdentKey, LateDecl, MacroRulesScope,
52-
Module, ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, PrivacyError, Res,
53-
ResolutionError, Resolver, Scope, ScopeSet, Segment, UseError, Used, VisResolutionError,
54-
errors as errs, path_names_to_string,
51+
DelayedVisResolutionError, Finalize, ForwardGenericParamBanReason, HasGenericParams, IdentKey,
52+
LateDecl, MacroRulesScope, Module, ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult,
53+
PrivacyError, Res, ResolutionError, Resolver, Scope, ScopeSet, Segment, UseError, Used,
54+
VisResolutionError, errors as errs, path_names_to_string,
5555
};
5656

5757
/// A vector of spans and replacements, a message and applicability.
@@ -137,6 +137,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
137137
}
138138

139139
pub(crate) fn report_errors(&mut self, krate: &Crate) {
140+
self.report_delayed_vis_resolution_errors();
140141
self.report_with_use_injections(krate);
141142

142143
for &(span_use, span_def) in &self.macro_expanded_macro_export_errors {
@@ -178,6 +179,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
178179
}
179180
}
180181

182+
fn report_delayed_vis_resolution_errors(&mut self) {
183+
for DelayedVisResolutionError { vis, parent_scope, error } in
184+
std::mem::take(&mut self.delayed_vis_resolution_errors)
185+
{
186+
match self.try_resolve_visibility(parent_scope, &vis, true, false) {
187+
Ok(_) => {
188+
self.report_vis_error(error);
189+
}
190+
Err(error) => {
191+
self.report_vis_error(error);
192+
}
193+
}
194+
}
195+
}
196+
181197
fn report_with_use_injections(&mut self, krate: &Crate) {
182198
for UseError { mut err, candidates, def_id, instead, suggestion, path, is_call } in
183199
std::mem::take(&mut self.use_injections)
@@ -1127,7 +1143,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
11271143

11281144
pub(crate) fn report_vis_error(
11291145
&mut self,
1130-
vis_resolution_error: VisResolutionError<'_>,
1146+
vis_resolution_error: VisResolutionError,
11311147
) -> ErrorGuaranteed {
11321148
match vis_resolution_error {
11331149
VisResolutionError::Relative2018(span, path) => {
@@ -1136,7 +1152,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
11361152
path_span: path.span,
11371153
// intentionally converting to String, as the text would also be used as
11381154
// in suggestion context
1139-
path_str: pprust::path_to_string(path),
1155+
path_str: pprust::path_to_string(&path),
11401156
})
11411157
}
11421158
VisResolutionError::AncestorOnly(span) => {

compiler/rustc_resolve/src/lib.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -336,8 +336,9 @@ enum ResolutionError<'ra> {
336336
BindingInNeverPattern,
337337
}
338338

339-
enum VisResolutionError<'a> {
340-
Relative2018(Span, &'a ast::Path),
339+
#[derive(Debug)]
340+
enum VisResolutionError {
341+
Relative2018(Span, ast::Path),
341342
AncestorOnly(Span),
342343
FailedToResolve(Span, Symbol, String, Option<Suggestion>, String),
343344
ExpectedFound(Span, String, Res),
@@ -997,6 +998,13 @@ struct UseError<'a> {
997998
is_call: bool,
998999
}
9991000

1001+
#[derive(Debug)]
1002+
struct DelayedVisResolutionError<'ra> {
1003+
vis: ast::Visibility,
1004+
parent_scope: ParentScope<'ra>,
1005+
error: VisResolutionError,
1006+
}
1007+
10001008
#[derive(Clone, Copy, PartialEq, Debug)]
10011009
enum AmbiguityKind {
10021010
BuiltinAttr,
@@ -1351,6 +1359,8 @@ pub struct Resolver<'ra, 'tcx> {
13511359
issue_145575_hack_applied: bool = false,
13521360
/// `use` injections are delayed for better placement and deduplication.
13531361
use_injections: Vec<UseError<'tcx>> = Vec::new(),
1362+
/// Visibility path resolution failures are delayed until all modules are collected.
1363+
delayed_vis_resolution_errors: Vec<DelayedVisResolutionError<'ra>> = Vec::new(),
13541364
/// Crate-local macro expanded `macro_export` referred to by a module-relative path.
13551365
macro_expanded_macro_export_errors: BTreeSet<(Span, Span)> = BTreeSet::new(),
13561366

tests/ui/privacy/restricted/test.stderr

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
1+
error[E0364]: `f` is private, and cannot be re-exported
2+
--> $DIR/test.rs:22:24
3+
|
4+
LL | pub(super) use foo::bar::f as g;
5+
| ^^^^^^^^^^^^^^^^
6+
|
7+
note: consider marking `f` as `pub` in the imported module
8+
--> $DIR/test.rs:22:24
9+
|
10+
LL | pub(super) use foo::bar::f as g;
11+
| ^^^^^^^^^^^^^^^^
12+
113
error[E0433]: cannot find module or crate `bad` in the crate root
214
--> $DIR/test.rs:51:12
315
|
@@ -15,18 +27,6 @@ error[E0742]: visibilities can only be restricted to ancestor modules
1527
LL | pub(in foo) mod m2 {}
1628
| ^^^
1729

18-
error[E0364]: `f` is private, and cannot be re-exported
19-
--> $DIR/test.rs:22:24
20-
|
21-
LL | pub(super) use foo::bar::f as g;
22-
| ^^^^^^^^^^^^^^^^
23-
|
24-
note: consider marking `f` as `pub` in the imported module
25-
--> $DIR/test.rs:22:24
26-
|
27-
LL | pub(super) use foo::bar::f as g;
28-
| ^^^^^^^^^^^^^^^^
29-
3030
error[E0603]: struct `Crate` is private
3131
--> $DIR/test.rs:39:25
3232
|

tests/ui/resolve/resolve-bad-visibility.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,9 @@ pub(in E) struct S; //~ ERROR expected module, found enum `::E`
66
pub(in Tr) struct Z; //~ ERROR expected module, found trait `::Tr`
77
pub(in std::vec) struct F; //~ ERROR visibilities can only be restricted to ancestor modules
88
pub(in nonexistent) struct G; //~ ERROR cannot find
9-
pub(in too_soon) struct H; //~ ERROR cannot find
9+
pub(in too_soon) struct H; //~ ERROR visibilities can only be restricted
1010

11-
// Visibilities are resolved eagerly without waiting for modules becoming fully populated.
12-
// Visibilities can only use ancestor modules legally which are always available in time,
13-
// so the worst thing that can happen due to eager resolution is a suboptimal error message.
11+
// The module exists, but it is not an ancestor module.
1412
mod too_soon {}
1513

1614
fn main () {}

tests/ui/resolve/resolve-bad-visibility.stderr

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,11 @@ help: you might be missing a crate named `nonexistent`, add it to your project a
2727
LL + extern crate nonexistent;
2828
|
2929

30-
error[E0433]: cannot find module or crate `too_soon` in the crate root
30+
error[E0742]: visibilities can only be restricted to ancestor modules
3131
--> $DIR/resolve-bad-visibility.rs:9:8
3232
|
3333
LL | pub(in too_soon) struct H;
34-
| ^^^^^^^^ use of unresolved module or unlinked crate `too_soon`
35-
|
36-
help: you might be missing a crate named `too_soon`, add it to your project and import it in your code
37-
|
38-
LL + extern crate too_soon;
39-
|
34+
| ^^^^^^^^
4035

4136
error: aborting due to 5 previous errors
4237

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
error[E0433]: cannot find `bar` in the crate root
2-
--> $DIR/visibility-indeterminate.rs:5:10
3-
|
4-
LL | pub(in ::bar) struct Baz {}
5-
| ^^^ could not find `bar` in the list of imported crates
6-
71
error: cannot find macro `foo` in this scope
82
--> $DIR/visibility-indeterminate.rs:3:1
93
|
104
LL | foo!();
115
| ^^^
126

7+
error[E0433]: cannot find `bar` in the crate root
8+
--> $DIR/visibility-indeterminate.rs:5:10
9+
|
10+
LL | pub(in ::bar) struct Baz {}
11+
| ^^^ could not find `bar` in the list of imported crates
12+
1313
error: aborting due to 2 previous errors
1414

1515
For more information about this error, try `rustc --explain E0433`.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//@ edition: 2021
2+
// Regression test for <https://github.com/rust-lang/rust/issues/40066>.
3+
4+
mod foo {
5+
pub(in crate::bar) struct Foo;
6+
//~^ ERROR visibilities can only be restricted to ancestor modules
7+
}
8+
9+
mod bar {
10+
pub(in crate::foo) struct Bar;
11+
//~^ ERROR visibilities can only be restricted to ancestor modules
12+
}
13+
14+
fn main() {}

0 commit comments

Comments
 (0)