Rollup merge of #150491 - petrochenkov:ambigeffvis, r=yaahc

resolve: Mark items under exported ambiguous imports as exported

After https://github.com/rust-lang/rust/pull/147984 one of the imports in an ambiguous import set becomes accessible under a deny-by-default deprecation lint.

So if it points to something, that something needs to be marked as exported, so its MIR is encoded into metadata, its symbol is not lost from object files, etc.
The added test shows an example.
This fixes around 10-20 crater regressions found in https://github.com/rust-lang/rust/pull/149195#issuecomment-3641704823.

Unblocks https://github.com/rust-lang/rust/pull/149195.
This commit is contained in:
Jonathan Brouwer 2026-01-28 21:10:48 +01:00 committed by GitHub
commit 8bdd8dc5e1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 60 additions and 32 deletions

View file

@ -96,13 +96,10 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> {
// is the maximum value among visibilities of declarations corresponding to that def id.
for (decl, eff_vis) in visitor.import_effective_visibilities.iter() {
let DeclKind::Import { import, .. } = decl.kind else { unreachable!() };
if !decl.is_ambiguity_recursive() {
if let Some(node_id) = import.id() {
r.effective_visibilities.update_eff_vis(r.local_def_id(node_id), eff_vis, r.tcx)
}
} else if decl.ambiguity.get().is_some()
&& eff_vis.is_public_at_level(Level::Reexported)
{
if let Some(node_id) = import.id() {
r.effective_visibilities.update_eff_vis(r.local_def_id(node_id), eff_vis, r.tcx)
}
if decl.ambiguity.get().is_some() && eff_vis.is_public_at_level(Level::Reexported) {
exported_ambiguities.insert(*decl);
}
}
@ -123,31 +120,13 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> {
// Set the given effective visibility level to `Level::Direct` and
// sets the rest of the `use` chain to `Level::Reexported` until
// we hit the actual exported item.
//
// If the binding is ambiguous, put the root ambiguity binding and all reexports
// leading to it into the table. They are used by the `ambiguous_glob_reexports`
// lint. For all bindings added to the table this way `is_ambiguity` returns true.
let is_ambiguity =
|decl: Decl<'ra>, warn: bool| decl.ambiguity.get().is_some() && !warn;
let mut parent_id = ParentId::Def(module_id);
let mut warn_ambiguity = decl.warn_ambiguity.get();
while let DeclKind::Import { source_decl, .. } = decl.kind {
self.update_import(decl, parent_id);
if is_ambiguity(decl, warn_ambiguity) {
// Stop at the root ambiguity, further bindings in the chain should not
// be reexported because the root ambiguity blocks any access to them.
// (Those further bindings are most likely not ambiguities themselves.)
break;
}
parent_id = ParentId::Import(decl);
decl = source_decl;
warn_ambiguity |= source_decl.warn_ambiguity.get();
}
if !is_ambiguity(decl, warn_ambiguity)
&& let Some(def_id) = decl.res().opt_def_id().and_then(|id| id.as_local())
{
if let Some(def_id) = decl.res().opt_def_id().and_then(|id| id.as_local()) {
self.update_def(def_id, decl.vis().expect_local(), parent_id);
}
}

View file

@ -1,9 +1,9 @@
//@ has 'glob_shadowing/index.html'
//@ count - '//dt' 6
//@ !has - '//dd' 'sub1::describe'
//@ count - '//dt' 7
//@ !has - '//dd' 'sub1::describe1'
//@ has - '//dd' 'sub2::describe'
//@ !has - '//dd' 'sub1::describe2'
//@ has - '//dd' 'sub1::describe2'
//@ !has - '//dd' 'sub1::prelude'
//@ has - '//dd' 'mod::prelude'
@ -18,7 +18,7 @@
mod sub1 {
// this should be shadowed by sub2::describe
/// sub1::describe
/// sub1::describe1
pub fn describe() -> &'static str {
"sub1::describe"
}
@ -33,7 +33,9 @@ mod sub1 {
pub struct Foo;
// this should be shadowed,
// because both sub1::describe2 and sub3::describe2 are from glob reexport
// because both sub1::describe2 and sub3::describe2 are from glob reexport,
// but it is still usable from other crates under the `ambiguous_glob_imports` lint,
// so it is reachable and documented
/// sub1::describe2
pub fn describe2() -> &'static str {
"sub1::describe2"

View file

@ -1,7 +1,9 @@
// Regression test for https://github.com/rust-lang/rust/issues/100973
// Update: the rules has changed after #147984, one of the colliding items is now available
// from other crates under a deprecation lint.
//@ set m1 = "$.index[?(@.name == 'm1' && @.inner.module)].id"
//@ is "$.index[?(@.name == 'm1')].inner.module.items" []
//@ is "$.index[?(@.name == 'm1')].inner.module.items" [0]
//@ is "$.index[?(@.name == 'm1')].inner.module.is_stripped" true
mod m1 {
pub fn f() {}

View file

@ -0,0 +1,8 @@
//@ build-pass
//@ aux-crate: ambiguous_reachable_extern=ambiguous-reachable-extern.rs
#![allow(ambiguous_glob_imports)]
fn main() {
ambiguous_reachable_extern::generic::<u8>();
}

View file

@ -0,0 +1,23 @@
Future incompatibility report: Future breakage diagnostic:
warning: `generic` is ambiguous
--> $DIR/ambiguous-reachable.rs:7:33
|
LL | ambiguous_reachable_extern::generic::<u8>();
| ^^^^^^^ ambiguous name
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #114095 <https://github.com/rust-lang/rust/issues/114095>
= note: ambiguous because of multiple glob imports of a name in the same module
note: `generic` could refer to the function defined here
--> $DIR/auxiliary/ambiguous-reachable-extern.rs:13:9
|
LL | pub use m1::*;
| ^^
= help: consider updating this dependency to resolve this error
= help: if updating the dependency does not resolve the problem report the problem to the author of the relevant crate
note: `generic` could also refer to the function defined here
--> $DIR/auxiliary/ambiguous-reachable-extern.rs:14:9
|
LL | pub use m2::*;
| ^^

View file

@ -0,0 +1,14 @@
mod m1 {
pub fn generic<T>() {
let x = 10;
let y = 11;
println!("hello {x} world {:?}", y);
}
}
mod m2 {
pub fn generic() {}
}
pub use m1::*;
pub use m2::*;