Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions compiler/rustc_resolve/src/build_reduced_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,16 +250,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
pub(crate) fn build_reduced_graph_external(&self, module: Module<'ra>) {
let def_id = module.def_id();
let children = self.tcx.module_children(def_id);
let parent_scope = ParentScope::module(module, self.arenas);
for (i, child) in children.iter().enumerate() {
self.build_reduced_graph_for_external_crate_res(child, parent_scope, i, None)
self.build_reduced_graph_for_external_crate_res(child, module, i, None)
}
for (i, child) in
self.cstore().ambig_module_children_untracked(self.tcx, def_id).enumerate()
{
self.build_reduced_graph_for_external_crate_res(
&child.main,
parent_scope,
module,
children.len() + i,
Some(&child.second),
)
Expand All @@ -270,11 +269,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
fn build_reduced_graph_for_external_crate_res(
&self,
child: &ModChild,
parent_scope: ParentScope<'ra>,
parent: Module<'ra>,
child_index: usize,
ambig_child: Option<&ModChild>,
) {
let parent = parent_scope.module;
let child_span = |this: &Self, reexport_chain: &[Reexport], res: def::Res<_>| {
this.def_span(
reexport_chain
Expand All @@ -287,7 +285,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
let ident = IdentKey::new(orig_ident);
let span = child_span(self, reexport_chain, res);
let res = res.expect_non_local();
let expansion = parent_scope.expansion;
let expansion = LocalExpnId::ROOT;
let ambig = ambig_child.map(|ambig_child| {
let ModChild { ident: _, res, vis, ref reexport_chain } = *ambig_child;
let span = child_span(self, reexport_chain, res);
Expand Down
26 changes: 12 additions & 14 deletions compiler/rustc_resolve/src/ident.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use Namespace::*;
use rustc_ast::{self as ast, NodeId};
use rustc_errors::ErrorGuaranteed;
use rustc_hir::def::{DefKind, MacroKinds, Namespace, NonMacroAttrKind, PartialRes, PerNS};
use rustc_middle::ty::Visibility;
use rustc_middle::{bug, span_bug};
use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK;
use rustc_session::parse::feature_err;
Expand All @@ -24,9 +23,9 @@ use crate::late::{
use crate::macros::{MacroRulesScope, sub_namespace_match};
use crate::{
AmbiguityError, AmbiguityKind, AmbiguityWarning, BindingKey, CmResolver, Decl, DeclKind,
Determinacy, Finalize, IdentKey, ImportKind, LateDecl, Module, ModuleKind, ModuleOrUniformRoot,
ParentScope, PathResult, PrivacyError, Res, ResolutionError, Resolver, Scope, ScopeSet,
Segment, Stage, Symbol, Used, errors,
Determinacy, Finalize, IdentKey, ImportKind, ImportSummary, LateDecl, Module, ModuleKind,
ModuleOrUniformRoot, ParentScope, PathResult, PrivacyError, Res, ResolutionError, Resolver,
Scope, ScopeSet, Segment, Stage, Symbol, Used, errors,
};

#[derive(Copy, Clone)]
Expand Down Expand Up @@ -485,11 +484,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
// We do not need to report them if we are either in speculative resolution,
// or in late resolution when everything is already imported and expanded
// and no ambiguities exist.
let import_vis = match finalize {
let import = match finalize {
None | Some(Finalize { stage: Stage::Late, .. }) => {
return ControlFlow::Break(Ok(decl));
}
Some(Finalize { import_vis, .. }) => import_vis,
Some(Finalize { import, .. }) => import,
};

if let Some(&(innermost_decl, _)) = innermost_results.first() {
Expand All @@ -503,7 +502,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
decl,
scope,
&innermost_results,
import_vis,
import,
) {
// No need to search for more potential ambiguities, one is enough.
return ControlFlow::Break(Ok(innermost_decl));
Expand Down Expand Up @@ -790,19 +789,18 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
decl: Decl<'ra>,
scope: Scope<'ra>,
innermost_results: &[(Decl<'ra>, Scope<'ra>)],
import_vis: Option<Visibility>,
import: Option<ImportSummary>,
) -> bool {
let (innermost_decl, innermost_scope) = innermost_results[0];
let (res, innermost_res) = (decl.res(), innermost_decl.res());
let ambig_vis = if res != innermost_res {
None
} else if let Some(import_vis) = import_vis
&& let min =
(|d: Decl<'_>| d.vis().min(import_vis.to_def_id(), self.tcx).expect_local())
&& let (min1, min2) = (min(decl), min(innermost_decl))
&& min1 != min2
} else if let Some(import) = import
&& let vis1 = self.import_decl_vis(decl, import)
&& let vis2 = self.import_decl_vis(innermost_decl, import)
&& vis1 != vis2
{
Some((min1, min2))
Some((vis1, vis2))
} else {
return false;
};
Expand Down
71 changes: 52 additions & 19 deletions compiler/rustc_resolve/src/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,9 @@ use crate::errors::{
use crate::ref_mut::CmCell;
use crate::{
AmbiguityError, BindingKey, CmResolver, Decl, DeclData, DeclKind, Determinacy, Finalize,
IdentKey, ImportSuggestion, Module, ModuleOrUniformRoot, ParentScope, PathResult, PerNS,
ResolutionError, Resolver, ScopeSet, Segment, Used, module_to_string, names_to_string,
IdentKey, ImportSuggestion, ImportSummary, Module, ModuleOrUniformRoot, ParentScope,
PathResult, PerNS, ResolutionError, Resolver, ScopeSet, Segment, Used, module_to_string,
names_to_string,
};

type Res = def::Res<NodeId>;
Expand Down Expand Up @@ -269,6 +270,14 @@ impl<'ra> ImportData<'ra> {
ImportKind::MacroExport => Reexport::MacroExport,
}
}

fn summary(&self) -> ImportSummary {
ImportSummary {
vis: self.vis,
nearest_parent_mod: self.parent_scope.module.nearest_parent_mod().expect_local(),
is_single: matches!(self.kind, ImportKind::Single { .. }),
}
}
}

/// Records information about the resolution of a name in a namespace of a module.
Expand Down Expand Up @@ -329,9 +338,9 @@ struct UnresolvedImportError {

// Reexports of the form `pub use foo as bar;` where `foo` is `extern crate foo;`
// are permitted for backward-compatibility under a deprecation lint.
fn pub_use_of_private_extern_crate_hack(import: Import<'_>, decl: Decl<'_>) -> Option<NodeId> {
match (&import.kind, &decl.kind) {
(ImportKind::Single { .. }, DeclKind::Import { import: decl_import, .. })
fn pub_use_of_private_extern_crate_hack(import: ImportSummary, decl: Decl<'_>) -> Option<NodeId> {
match (import.is_single, decl.kind) {
(true, DeclKind::Import { import: decl_import, .. })
if let ImportKind::ExternCrate { id, .. } = decl_import.kind
&& import.vis.is_public() =>
{
Expand Down Expand Up @@ -363,31 +372,50 @@ fn remove_same_import<'ra>(d1: Decl<'ra>, d2: Decl<'ra>) -> (Decl<'ra>, Decl<'ra
}

impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
pub(crate) fn import_decl_vis(&self, decl: Decl<'ra>, import: ImportSummary) -> Visibility {
assert!(import.vis.is_accessible_from(import.nearest_parent_mod, self.tcx));
let decl_vis = decl.vis();
if decl_vis.is_at_least(import.vis, self.tcx) {
// Ordered, import is less visible than the imported declaration, or the same,
// use the import's visibility.
import.vis
} else if decl_vis.is_accessible_from(import.nearest_parent_mod, self.tcx) {
// Ordered, imported declaration is less visible than the import, but is still visible
// from the current module, use the declaration's visibility.
assert!(import.vis.is_at_least(decl_vis, self.tcx));
if pub_use_of_private_extern_crate_hack(import, decl).is_some() {
import.vis
} else {
decl_vis.expect_local()
}
} else {
// Ordered or not, the imported declaration is too private for the current module.
// It doesn't matter what visibility we choose here (except in the `PRIVATE_MACRO_USE`
// case), because either some error will be reported, or the import declaration
// will be thrown away (unfortunately cannot use delayed bug here for this reason).
// Use import visibility to keep the all declaration visibilities in a module ordered.
import.vis
}
}

/// Given an import and the declaration that it points to,
/// create the corresponding import declaration.
pub(crate) fn new_import_decl(&self, decl: Decl<'ra>, import: Import<'ra>) -> Decl<'ra> {
let import_vis = import.vis.to_def_id();
let vis = if decl.vis().is_at_least(import_vis, self.tcx)
|| pub_use_of_private_extern_crate_hack(import, decl).is_some()
{
import_vis
} else {
decl.vis()
};
let vis = self.import_decl_vis(decl, import.summary());

if let ImportKind::Glob { ref max_vis, .. } = import.kind
&& (vis == import_vis
&& (vis == import.vis
|| max_vis.get().is_none_or(|max_vis| vis.is_at_least(max_vis, self.tcx)))
{
max_vis.set_unchecked(Some(vis.expect_local()))
max_vis.set_unchecked(Some(vis))
}

self.arenas.alloc_decl(DeclData {
kind: DeclKind::Import { source_decl: decl, import },
ambiguity: CmCell::new(None),
warn_ambiguity: CmCell::new(false),
span: import.span,
vis: CmCell::new(vis),
vis: CmCell::new(vis.to_def_id()),
expansion: import.parent_scope.expansion,
parent_module: Some(import.parent_scope.module),
})
Expand Down Expand Up @@ -450,6 +478,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
} else if !old_glob_decl.vis().is_at_least(glob_decl.vis(), self.tcx) {
// We are glob-importing the same item but with greater visibility.
// All visibilities here are ordered because all of them are ancestors of `module`.
// FIXME: Update visibility in place, but without regressions
// (#152004, #151124, #152347).
glob_decl
Expand All @@ -473,7 +502,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
decl: Decl<'ra>,
warn_ambiguity: bool,
) -> Result<(), Decl<'ra>> {
assert!(!decl.warn_ambiguity.get());
assert!(decl.ambiguity.get().is_none());
let module = decl.parent_module.unwrap();
assert!(self.is_accessible_from(decl.vis(), module));
let res = decl.res();
self.check_reserved_macro_name(ident.name, orig_ident_span, res);
// Even if underscore names cannot be looked up, we still need to add them to modules,
Expand All @@ -489,7 +521,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
orig_ident_span,
warn_ambiguity,
|this, resolution| {
assert!(!decl.warn_ambiguity.get());
if decl.is_glob_import() {
resolution.glob_decl = Some(match resolution.glob_decl {
Some(old_decl) => this.select_glob_decl(
Expand Down Expand Up @@ -1264,7 +1295,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
&import.parent_scope,
Some(Finalize {
report_private: false,
import_vis: Some(import.vis),
import: Some(import.summary()),
..finalize
}),
bindings[ns].get().decl(),
Expand Down Expand Up @@ -1464,7 +1495,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
// All namespaces must be re-exported with extra visibility for an error to occur.
if !any_successful_reexport {
let (ns, binding) = reexport_error.unwrap();
if let Some(extern_crate_id) = pub_use_of_private_extern_crate_hack(import, binding) {
if let Some(extern_crate_id) =
pub_use_of_private_extern_crate_hack(import.summary(), binding)
{
let extern_crate_sp = self.tcx.source_span(self.local_def_id(extern_crate_id));
self.lint_buffer.buffer_lint(
PUB_USE_OF_PRIVATE_EXTERN_CRATE,
Expand Down
13 changes: 11 additions & 2 deletions compiler/rustc_resolve/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2641,6 +2641,15 @@ enum Stage {
Late,
}

/// Parts of import data required for finalizing import resolution.
/// Does not carry a lifetime, so it can be stored in `Finalize`.
#[derive(Copy, Clone, Debug)]
struct ImportSummary {
vis: Visibility,
nearest_parent_mod: LocalDefId,
is_single: bool,
}

/// Invariant: if `Finalize` is used, expansion and import resolution must be complete.
#[derive(Copy, Clone, Debug)]
struct Finalize {
Expand All @@ -2659,8 +2668,8 @@ struct Finalize {
used: Used = Used::Other,
/// Finalizing early or late resolution.
stage: Stage = Stage::Early,
/// Nominal visibility of the import item, in case we are resolving an import's final segment.
import_vis: Option<Visibility> = None,
/// Some import data, in case we are resolving an import's final segment.
import: Option<ImportSummary> = None,
}

impl Finalize {
Expand Down
23 changes: 23 additions & 0 deletions tests/ui/imports/ambiguous-import-visibility-globglob-priv-pass.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//@ check-pass

mod m {
pub struct S {}
}

mod one_private {
use crate::m::*;
pub use crate::m::*;
}

// One of the ambiguous imports is not visible from here,
// and does not contribute to the ambiguity.
use crate::one_private::S;

// Separate module to make visibilities `in crate::inner` and `in crate::one_private` unordered.
mod inner {
// One of the ambiguous imports is not visible from here,
// and does not contribute to the ambiguity.
use crate::one_private::S;
}

fn main() {}
21 changes: 21 additions & 0 deletions tests/ui/imports/ambiguous-import-visibility-globglob-priv.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
mod m {
pub struct S {}
}

mod both {
pub mod private {
use crate::m::*;
pub(super) use crate::m::*;
}
}

use crate::both::private::S;
//~^ ERROR struct import `S` is private

// Separate module to make visibilities `in crate::inner` and `in crate::both::private` unordered.
mod inner {
use crate::both::private::S;
//~^ ERROR struct import `S` is private
}

fn main() {}
47 changes: 47 additions & 0 deletions tests/ui/imports/ambiguous-import-visibility-globglob-priv.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
error[E0603]: struct import `S` is private
--> $DIR/ambiguous-import-visibility-globglob-priv.rs:12:27
|
LL | use crate::both::private::S;
| ^ private struct import
|
note: the struct import `S` is defined here...
--> $DIR/ambiguous-import-visibility-globglob-priv.rs:8:24
|
LL | pub(super) use crate::m::*;
| ^^^^^^^^^^^
note: ...and refers to the struct `S` which is defined here
--> $DIR/ambiguous-import-visibility-globglob-priv.rs:2:5
|
LL | pub struct S {}
| ^^^^^^^^^^^^ you could import this directly
help: import `S` through the re-export
|
LL - use crate::both::private::S;
LL + use m::S;
|

error[E0603]: struct import `S` is private
--> $DIR/ambiguous-import-visibility-globglob-priv.rs:17:31
|
LL | use crate::both::private::S;
| ^ private struct import
|
note: the struct import `S` is defined here...
--> $DIR/ambiguous-import-visibility-globglob-priv.rs:8:24
|
LL | pub(super) use crate::m::*;
| ^^^^^^^^^^^
note: ...and refers to the struct `S` which is defined here
--> $DIR/ambiguous-import-visibility-globglob-priv.rs:2:5
|
LL | pub struct S {}
| ^^^^^^^^^^^^ you could import this directly
help: import `S` through the re-export
|
LL - use crate::both::private::S;
LL + use m::S;
|

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0603`.
Loading
Loading