Merge pull request #18390 from ShoyuVanilla/issue-18308

fix: Prevent public re-export of private item
This commit is contained in:
Lukas Wirth 2024-10-24 09:25:06 +00:00 committed by GitHub
commit 981ea1955c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 98 additions and 9 deletions

View File

@ -1025,7 +1025,7 @@ fn same_crate_reexport() {
check_found_path(
r#"
mod bar {
mod foo { pub(super) struct S; }
mod foo { pub(crate) struct S; }
pub(crate) use foo::*;
}
$0
@ -1047,7 +1047,7 @@ fn same_crate_reexport_rename() {
check_found_path(
r#"
mod bar {
mod foo { pub(super) struct S; }
mod foo { pub(crate) struct S; }
pub(crate) use foo::S as U;
}
$0

View File

@ -985,12 +985,8 @@ fn update_recursive(
for (name, res) in resolutions {
match name {
Some(name) => {
changed |= self.push_res_and_update_glob_vis(
module_id,
name,
res.with_visibility(vis),
import,
);
changed |=
self.push_res_and_update_glob_vis(module_id, name, *res, vis, import);
}
None => {
let tr = match res.take_types() {
@ -1043,10 +1039,11 @@ fn update_recursive(
.collect::<Vec<_>>();
for (glob_importing_module, glob_import_vis, use_) in glob_imports {
let vis = glob_import_vis.min(vis, &self.def_map).unwrap_or(glob_import_vis);
self.update_recursive(
glob_importing_module,
resolutions,
glob_import_vis,
vis,
Some(ImportType::Glob(use_)),
depth + 1,
);
@ -1058,8 +1055,19 @@ fn push_res_and_update_glob_vis(
module_id: LocalModuleId,
name: &Name,
mut defs: PerNs,
vis: Visibility,
def_import_type: Option<ImportType>,
) -> bool {
if let Some((_, v, _)) = defs.types.as_mut() {
*v = v.min(vis, &self.def_map).unwrap_or(vis);
}
if let Some((_, v, _)) = defs.values.as_mut() {
*v = v.min(vis, &self.def_map).unwrap_or(vis);
}
if let Some((_, v, _)) = defs.macros.as_mut() {
*v = v.min(vis, &self.def_map).unwrap_or(vis);
}
let mut changed = false;
if let Some(ImportType::Glob(_)) = def_import_type {

View File

@ -412,3 +412,42 @@ pub fn function() {}
"#]],
);
}
#[test]
fn regression_18308() {
check(
r#"
use outer::*;
mod outer {
mod inner_superglob {
pub use super::*;
}
// The importing order matters!
pub use inner_superglob::*;
use super::glob_target::*;
}
mod glob_target {
pub struct ShouldBePrivate;
}
"#,
expect![[r#"
crate
glob_target: t
outer: t
crate::glob_target
ShouldBePrivate: t v
crate::outer
ShouldBePrivate: t v
inner_superglob: t
crate::outer::inner_superglob
ShouldBePrivate: t v
inner_superglob: t
"#]],
);
}

View File

@ -191,6 +191,11 @@ pub(crate) fn max(self, other: Visibility, def_map: &DefMap) -> Option<Visibilit
return None;
}
let def_block = def_map.block_id();
if (mod_a.containing_block(), mod_b.containing_block()) != (def_block, def_block) {
return None;
}
let mut a_ancestors =
iter::successors(Some(mod_a.local_id), |&m| def_map[m].parent);
let mut b_ancestors =
@ -210,6 +215,43 @@ pub(crate) fn max(self, other: Visibility, def_map: &DefMap) -> Option<Visibilit
}
}
}
/// Returns the least permissive visibility of `self` and `other`.
///
/// If there is no subset relation between `self` and `other`, returns `None` (ie. they're only
/// visible in unrelated modules).
pub(crate) fn min(self, other: Visibility, def_map: &DefMap) -> Option<Visibility> {
match (self, other) {
(vis, Visibility::Public) | (Visibility::Public, vis) => Some(vis),
(Visibility::Module(mod_a, expl_a), Visibility::Module(mod_b, expl_b)) => {
if mod_a.krate != mod_b.krate {
return None;
}
let def_block = def_map.block_id();
if (mod_a.containing_block(), mod_b.containing_block()) != (def_block, def_block) {
return None;
}
let mut a_ancestors =
iter::successors(Some(mod_a.local_id), |&m| def_map[m].parent);
let mut b_ancestors =
iter::successors(Some(mod_b.local_id), |&m| def_map[m].parent);
if a_ancestors.any(|m| m == mod_b.local_id) {
// B is above A
return Some(Visibility::Module(mod_a, expl_b));
}
if b_ancestors.any(|m| m == mod_a.local_id) {
// A is above B
return Some(Visibility::Module(mod_b, expl_a));
}
None
}
}
}
}
/// Whether the item was imported through an explicit `pub(crate) use` or just a `use` without