diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 6310155154b95..bb0e96d2f356a 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -35,9 +35,10 @@ use crate::imports::{ImportData, ImportKind, OnUnknownData}; use crate::macros::{MacroRulesDecl, MacroRulesScope, MacroRulesScopeRef}; use crate::ref_mut::CmCell; use crate::{ - BindingKey, Decl, DeclData, DeclKind, ExternModule, ExternPreludeEntry, Finalize, IdentKey, - LocalModule, MacroData, Module, ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, Res, - Resolver, Segment, Used, VisResolutionError, errors, + BindingKey, Decl, DeclData, DeclKind, DelayedVisResolutionError, ExternModule, + ExternPreludeEntry, Finalize, IdentKey, LocalModule, MacroData, Module, ModuleKind, + ModuleOrUniformRoot, ParentScope, PathResult, Res, Resolver, Segment, Used, VisResolutionError, + errors, }; impl<'ra, 'tcx> Resolver<'ra, 'tcx> { @@ -235,6 +236,111 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } + pub(crate) fn try_resolve_visibility( + &mut self, + parent_scope: &ParentScope<'ra>, + vis: &ast::Visibility, + finalize: bool, + ) -> Result { + match vis.kind { + ast::VisibilityKind::Public => Ok(Visibility::Public), + ast::VisibilityKind::Inherited => { + Ok(match parent_scope.module.kind { + // Any inherited visibility resolved directly inside an enum or trait + // (i.e. variants, fields, and trait items) inherits from the visibility + // of the enum or trait. + ModuleKind::Def(DefKind::Enum | DefKind::Trait, def_id, _) => { + self.tcx.visibility(def_id).expect_local() + } + // Otherwise, the visibility is restricted to the nearest parent `mod` item. + _ => Visibility::Restricted( + parent_scope.module.nearest_parent_mod().expect_local(), + ), + }) + } + ast::VisibilityKind::Restricted { ref path, id, .. } => { + // For visibilities we are not ready to provide correct implementation of "uniform + // paths" right now, so on 2018 edition we only allow module-relative paths for now. + // On 2015 edition visibilities are resolved as crate-relative by default, + // so we are prepending a root segment if necessary. + let ident = path.segments.get(0).expect("empty path in visibility").ident; + let crate_root = if ident.is_path_segment_keyword() { + None + } else if ident.span.is_rust_2015() { + Some(Segment::from_ident(Ident::new( + kw::PathRoot, + path.span.shrink_to_lo().with_ctxt(ident.span.ctxt()), + ))) + } else { + return Err(VisResolutionError::Relative2018( + ident.span, + path.as_ref().clone(), + )); + }; + let segments = crate_root + .into_iter() + .chain(path.segments.iter().map(|seg| seg.into())) + .collect::>(); + let expected_found_error = |res| { + Err(VisResolutionError::ExpectedFound( + path.span, + Segment::names_to_string(&segments), + res, + )) + }; + match self.cm().resolve_path( + &segments, + None, + parent_scope, + finalize.then(|| Finalize::new(id, path.span)), + None, + None, + ) { + PathResult::Module(ModuleOrUniformRoot::Module(module)) => { + let res = module.res().expect("visibility resolved to unnamed block"); + if module.is_normal() { + match res { + Res::Err => { + if finalize { + self.record_partial_res(id, PartialRes::new(res)); + } + Ok(Visibility::Public) + } + _ => { + let vis = Visibility::Restricted(res.def_id()); + if self.is_accessible_from(vis, parent_scope.module) { + if finalize { + self.record_partial_res(id, PartialRes::new(res)); + } + Ok(vis.expect_local()) + } else { + Err(VisResolutionError::AncestorOnly(path.span)) + } + } + } + } else { + expected_found_error(res) + } + } + PathResult::Module(..) => Err(VisResolutionError::ModuleOnly(path.span)), + PathResult::NonModule(partial_res) => { + expected_found_error(partial_res.expect_full_res()) + } + PathResult::Failed { + span, label, suggestion, message, segment_name, .. + } => Err(VisResolutionError::FailedToResolve( + span, + segment_name, + label, + suggestion, + message, + )), + PathResult::Indeterminate => Err(VisResolutionError::Indeterminate(path.span)), + } + } + } + } + pub(crate) fn build_reduced_graph_external(&self, module: ExternModule<'ra>) { let def_id = module.def_id(); let children = self.tcx.module_children(def_id); @@ -362,106 +468,15 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { } fn resolve_visibility(&mut self, vis: &ast::Visibility) -> Visibility { - self.try_resolve_visibility(vis, true).unwrap_or_else(|err| { - self.r.report_vis_error(err); - Visibility::Public - }) - } - - fn try_resolve_visibility<'ast>( - &mut self, - vis: &'ast ast::Visibility, - finalize: bool, - ) -> Result> { - let parent_scope = &self.parent_scope; - match vis.kind { - ast::VisibilityKind::Public => Ok(Visibility::Public), - ast::VisibilityKind::Inherited => { - Ok(match self.parent_scope.module.kind { - // Any inherited visibility resolved directly inside an enum or trait - // (i.e. variants, fields, and trait items) inherits from the visibility - // of the enum or trait. - ModuleKind::Def(DefKind::Enum | DefKind::Trait, def_id, _) => { - self.r.tcx.visibility(def_id).expect_local() - } - // Otherwise, the visibility is restricted to the nearest parent `mod` item. - _ => Visibility::Restricted( - self.parent_scope.module.nearest_parent_mod().expect_local(), - ), - }) - } - ast::VisibilityKind::Restricted { ref path, id, .. } => { - // For visibilities we are not ready to provide correct implementation of "uniform - // paths" right now, so on 2018 edition we only allow module-relative paths for now. - // On 2015 edition visibilities are resolved as crate-relative by default, - // so we are prepending a root segment if necessary. - let ident = path.segments.get(0).expect("empty path in visibility").ident; - let crate_root = if ident.is_path_segment_keyword() { - None - } else if ident.span.is_rust_2015() { - Some(Segment::from_ident(Ident::new( - kw::PathRoot, - path.span.shrink_to_lo().with_ctxt(ident.span.ctxt()), - ))) - } else { - return Err(VisResolutionError::Relative2018(ident.span, path)); - }; - - let segments = crate_root - .into_iter() - .chain(path.segments.iter().map(|seg| seg.into())) - .collect::>(); - let expected_found_error = |res| { - Err(VisResolutionError::ExpectedFound( - path.span, - Segment::names_to_string(&segments), - res, - )) - }; - match self.r.cm().resolve_path( - &segments, - None, - parent_scope, - finalize.then(|| Finalize::new(id, path.span)), - None, - None, - ) { - PathResult::Module(ModuleOrUniformRoot::Module(module)) => { - let res = module.res().expect("visibility resolved to unnamed block"); - if finalize { - self.r.record_partial_res(id, PartialRes::new(res)); - } - if module.is_normal() { - match res { - Res::Err => Ok(Visibility::Public), - _ => { - let vis = Visibility::Restricted(res.def_id()); - if self.r.is_accessible_from(vis, parent_scope.module) { - Ok(vis.expect_local()) - } else { - Err(VisResolutionError::AncestorOnly(path.span)) - } - } - } - } else { - expected_found_error(res) - } - } - PathResult::Module(..) => Err(VisResolutionError::ModuleOnly(path.span)), - PathResult::NonModule(partial_res) => { - expected_found_error(partial_res.expect_full_res()) - } - PathResult::Failed { - span, label, suggestion, message, segment_name, .. - } => Err(VisResolutionError::FailedToResolve( - span, - segment_name, - label, - suggestion, - message, - )), - PathResult::Indeterminate => Err(VisResolutionError::Indeterminate(path.span)), - } + match self.r.try_resolve_visibility(&self.parent_scope, vis, true) { + Ok(vis) => vis, + Err(error) => { + self.r.delayed_vis_resolution_errors.push(DelayedVisResolutionError { + vis: vis.clone(), + parent_scope: self.parent_scope, + error, + }); + Visibility::Public } } } @@ -904,7 +919,8 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { // correct visibilities for unnamed field placeholders specifically, so the // constructor visibility should still be determined correctly. let field_vis = self - .try_resolve_visibility(&field.vis, false) + .r + .try_resolve_visibility(&self.parent_scope, &field.vis, false) .unwrap_or(Visibility::Public); if ctor_vis.greater_than(field_vis, self.r.tcx) { ctor_vis = field_vis; @@ -1339,9 +1355,10 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { let vis = match item.kind { // Visibilities must not be resolved non-speculatively twice // and we already resolved this one as a `fn` item visibility. - ItemKind::Fn(..) => { - self.try_resolve_visibility(&item.vis, false).unwrap_or(Visibility::Public) - } + ItemKind::Fn(..) => self + .r + .try_resolve_visibility(&self.parent_scope, &item.vis, false) + .unwrap_or(Visibility::Public), _ => self.resolve_visibility(&item.vis), }; if !vis.is_public() { diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 723890a2f1ca2..800da479d39d2 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1,4 +1,5 @@ // ignore-tidy-filelength +use std::mem; use std::ops::ControlFlow; use itertools::Itertools as _; @@ -48,10 +49,10 @@ use crate::imports::{Import, ImportKind}; use crate::late::{DiagMetadata, PatternSource, Rib}; use crate::{ AmbiguityError, AmbiguityKind, AmbiguityWarning, BindingError, BindingKey, Decl, DeclKind, - Finalize, ForwardGenericParamBanReason, HasGenericParams, IdentKey, LateDecl, MacroRulesScope, - Module, ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, PrivacyError, Res, - ResolutionError, Resolver, Scope, ScopeSet, Segment, UseError, Used, VisResolutionError, - errors as errs, path_names_to_string, + DelayedVisResolutionError, Finalize, ForwardGenericParamBanReason, HasGenericParams, IdentKey, + LateDecl, MacroRulesScope, Module, ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, + PrivacyError, Res, ResolutionError, Resolver, Scope, ScopeSet, Segment, UseError, Used, + VisResolutionError, errors as errs, path_names_to_string, }; /// A vector of spans and replacements, a message and applicability. @@ -137,6 +138,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } pub(crate) fn report_errors(&mut self, krate: &Crate) { + self.report_delayed_vis_resolution_errors(); self.report_with_use_injections(krate); for &(span_use, span_def) in &self.macro_expanded_macro_export_errors { @@ -171,16 +173,27 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let mut reported_spans = FxHashSet::default(); - for error in std::mem::take(&mut self.privacy_errors) { + for error in mem::take(&mut self.privacy_errors) { if reported_spans.insert(error.dedup_span) { self.report_privacy_error(&error); } } } + fn report_delayed_vis_resolution_errors(&mut self) { + for DelayedVisResolutionError { vis, parent_scope, error } in + mem::take(&mut self.delayed_vis_resolution_errors) + { + match self.try_resolve_visibility(&parent_scope, &vis, true) { + Ok(_) => self.report_vis_error(error), + Err(error) => self.report_vis_error(error), + }; + } + } + fn report_with_use_injections(&mut self, krate: &Crate) { for UseError { mut err, candidates, def_id, instead, suggestion, path, is_call } in - std::mem::take(&mut self.use_injections) + mem::take(&mut self.use_injections) { let (span, found_use) = if let Some(def_id) = def_id.as_local() { UsePlacementFinder::check(krate, self.def_id_to_node_id(def_id)) @@ -1127,7 +1140,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { pub(crate) fn report_vis_error( &mut self, - vis_resolution_error: VisResolutionError<'_>, + vis_resolution_error: VisResolutionError, ) -> ErrorGuaranteed { match vis_resolution_error { VisResolutionError::Relative2018(span, path) => { @@ -1136,7 +1149,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { path_span: path.span, // intentionally converting to String, as the text would also be used as // in suggestion context - path_str: pprust::path_to_string(path), + path_str: pprust::path_to_string(&path), }) } VisResolutionError::AncestorOnly(span) => { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 3b8f3c4a24c90..811cdcb0021e4 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -336,8 +336,9 @@ enum ResolutionError<'ra> { BindingInNeverPattern, } -enum VisResolutionError<'a> { - Relative2018(Span, &'a ast::Path), +#[derive(Debug)] +enum VisResolutionError { + Relative2018(Span, ast::Path), AncestorOnly(Span), FailedToResolve(Span, Symbol, String, Option, String), ExpectedFound(Span, String, Res), @@ -997,6 +998,13 @@ struct UseError<'a> { is_call: bool, } +#[derive(Debug)] +struct DelayedVisResolutionError<'ra> { + vis: ast::Visibility, + parent_scope: ParentScope<'ra>, + error: VisResolutionError, +} + #[derive(Clone, Copy, PartialEq, Debug)] enum AmbiguityKind { BuiltinAttr, @@ -1351,6 +1359,8 @@ pub struct Resolver<'ra, 'tcx> { issue_145575_hack_applied: bool = false, /// `use` injections are delayed for better placement and deduplication. use_injections: Vec> = Vec::new(), + /// Visibility path resolution failures are delayed until all modules are collected. + delayed_vis_resolution_errors: Vec> = Vec::new(), /// Crate-local macro expanded `macro_export` referred to by a module-relative path. macro_expanded_macro_export_errors: BTreeSet<(Span, Span)> = BTreeSet::new(), diff --git a/tests/ui/privacy/restricted/test.stderr b/tests/ui/privacy/restricted/test.stderr index ae56e0bf78443..f380da1ca344e 100644 --- a/tests/ui/privacy/restricted/test.stderr +++ b/tests/ui/privacy/restricted/test.stderr @@ -1,3 +1,15 @@ +error[E0364]: `f` is private, and cannot be re-exported + --> $DIR/test.rs:22:24 + | +LL | pub(super) use foo::bar::f as g; + | ^^^^^^^^^^^^^^^^ + | +note: consider marking `f` as `pub` in the imported module + --> $DIR/test.rs:22:24 + | +LL | pub(super) use foo::bar::f as g; + | ^^^^^^^^^^^^^^^^ + error[E0433]: cannot find module or crate `bad` in the crate root --> $DIR/test.rs:51:12 | @@ -15,18 +27,6 @@ error[E0742]: visibilities can only be restricted to ancestor modules LL | pub(in foo) mod m2 {} | ^^^ -error[E0364]: `f` is private, and cannot be re-exported - --> $DIR/test.rs:22:24 - | -LL | pub(super) use foo::bar::f as g; - | ^^^^^^^^^^^^^^^^ - | -note: consider marking `f` as `pub` in the imported module - --> $DIR/test.rs:22:24 - | -LL | pub(super) use foo::bar::f as g; - | ^^^^^^^^^^^^^^^^ - error[E0603]: struct `Crate` is private --> $DIR/test.rs:39:25 | diff --git a/tests/ui/resolve/resolve-bad-visibility.rs b/tests/ui/resolve/resolve-bad-visibility.rs index bfc5e90c31e71..dfae5f23864a0 100644 --- a/tests/ui/resolve/resolve-bad-visibility.rs +++ b/tests/ui/resolve/resolve-bad-visibility.rs @@ -6,11 +6,9 @@ pub(in E) struct S; //~ ERROR expected module, found enum `::E` pub(in Tr) struct Z; //~ ERROR expected module, found trait `::Tr` pub(in std::vec) struct F; //~ ERROR visibilities can only be restricted to ancestor modules pub(in nonexistent) struct G; //~ ERROR cannot find -pub(in too_soon) struct H; //~ ERROR cannot find +pub(in too_soon) struct H; //~ ERROR visibilities can only be restricted -// Visibilities are resolved eagerly without waiting for modules becoming fully populated. -// Visibilities can only use ancestor modules legally which are always available in time, -// so the worst thing that can happen due to eager resolution is a suboptimal error message. +// The module exists, but it is not an ancestor module. mod too_soon {} fn main () {} diff --git a/tests/ui/resolve/resolve-bad-visibility.stderr b/tests/ui/resolve/resolve-bad-visibility.stderr index d9fd4400b8e0e..1965750a79b23 100644 --- a/tests/ui/resolve/resolve-bad-visibility.stderr +++ b/tests/ui/resolve/resolve-bad-visibility.stderr @@ -27,16 +27,11 @@ help: you might be missing a crate named `nonexistent`, add it to your project a LL + extern crate nonexistent; | -error[E0433]: cannot find module or crate `too_soon` in the crate root +error[E0742]: visibilities can only be restricted to ancestor modules --> $DIR/resolve-bad-visibility.rs:9:8 | LL | pub(in too_soon) struct H; - | ^^^^^^^^ use of unresolved module or unlinked crate `too_soon` - | -help: you might be missing a crate named `too_soon`, add it to your project and import it in your code - | -LL + extern crate too_soon; - | + | ^^^^^^^^ error: aborting due to 5 previous errors diff --git a/tests/ui/resolve/visibility-indeterminate.stderr b/tests/ui/resolve/visibility-indeterminate.stderr index bd6fc11b67313..d58d45ab792b4 100644 --- a/tests/ui/resolve/visibility-indeterminate.stderr +++ b/tests/ui/resolve/visibility-indeterminate.stderr @@ -1,15 +1,15 @@ -error[E0433]: cannot find `bar` in the crate root - --> $DIR/visibility-indeterminate.rs:5:10 - | -LL | pub(in ::bar) struct Baz {} - | ^^^ could not find `bar` in the list of imported crates - error: cannot find macro `foo` in this scope --> $DIR/visibility-indeterminate.rs:3:1 | LL | foo!(); | ^^^ +error[E0433]: cannot find `bar` in the crate root + --> $DIR/visibility-indeterminate.rs:5:10 + | +LL | pub(in ::bar) struct Baz {} + | ^^^ could not find `bar` in the list of imported crates + error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/resolve/visibility-order-dependent.rs b/tests/ui/resolve/visibility-order-dependent.rs new file mode 100644 index 0000000000000..984e9a3aae6a2 --- /dev/null +++ b/tests/ui/resolve/visibility-order-dependent.rs @@ -0,0 +1,14 @@ +//@ edition: 2021 +// Regression test for . + +mod foo { + pub(in crate::bar) struct Foo; + //~^ ERROR visibilities can only be restricted to ancestor modules +} + +mod bar { + pub(in crate::foo) struct Bar; + //~^ ERROR visibilities can only be restricted to ancestor modules +} + +fn main() {} diff --git a/tests/ui/resolve/visibility-order-dependent.stderr b/tests/ui/resolve/visibility-order-dependent.stderr new file mode 100644 index 0000000000000..4bc7b37c6ac95 --- /dev/null +++ b/tests/ui/resolve/visibility-order-dependent.stderr @@ -0,0 +1,15 @@ +error[E0742]: visibilities can only be restricted to ancestor modules + --> $DIR/visibility-order-dependent.rs:5:12 + | +LL | pub(in crate::bar) struct Foo; + | ^^^^^^^^^^ + +error[E0742]: visibilities can only be restricted to ancestor modules + --> $DIR/visibility-order-dependent.rs:10:12 + | +LL | pub(in crate::foo) struct Bar; + | ^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0742`. diff --git a/tests/ui/span/visibility-ty-params.stderr b/tests/ui/span/visibility-ty-params.stderr index 2fda6c70de0dd..08c1552d7fbbb 100644 --- a/tests/ui/span/visibility-ty-params.stderr +++ b/tests/ui/span/visibility-ty-params.stderr @@ -4,18 +4,18 @@ error: unexpected generic arguments in path LL | m!{ crate::S } | ^^^^ -error[E0433]: cannot find module `S` in `crate` - --> $DIR/visibility-ty-params.rs:6:12 - | -LL | m!{ crate::S } - | ^ `S` is a struct, not a module - error: unexpected generic arguments in path --> $DIR/visibility-ty-params.rs:10:17 | LL | m!{ crate::m<> } | ^^ +error[E0433]: cannot find module `S` in `crate` + --> $DIR/visibility-ty-params.rs:6:12 + | +LL | m!{ crate::S } + | ^ `S` is a struct, not a module + error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/use/use-self-type.stderr b/tests/ui/use/use-self-type.stderr index 086b7a4d8222c..e1258d3509e87 100644 --- a/tests/ui/use/use-self-type.stderr +++ b/tests/ui/use/use-self-type.stderr @@ -1,15 +1,15 @@ -error[E0433]: cannot find `Self` in this scope - --> $DIR/use-self-type.rs:7:16 - | -LL | pub(in Self::f) struct Z; - | ^^^^ `Self` cannot be used in imports - error[E0432]: unresolved import `Self` --> $DIR/use-self-type.rs:6:13 | LL | use Self::f; | ^^^^ `Self` cannot be used in imports +error[E0433]: cannot find `Self` in this scope + --> $DIR/use-self-type.rs:7:16 + | +LL | pub(in Self::f) struct Z; + | ^^^^ `Self` cannot be used in imports + error: aborting due to 2 previous errors Some errors have detailed explanations: E0432, E0433.