Skip to content

Commit d28ea81

Browse files
committed
resolve: Extend ambiguous_import_visibilities deprecation lint to glob-vs-glob ambiguities
1 parent c935696 commit d28ea81

11 files changed

Lines changed: 256 additions & 48 deletions

compiler/rustc_middle/src/middle/privacy.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use std::hash::Hash;
88
use rustc_data_structures::fx::{FxIndexMap, IndexEntry};
99
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
1010
use rustc_hir::def::DefKind;
11+
use rustc_hir::{ItemKind, Node, UseKind};
1112
use rustc_macros::HashStable;
1213
use rustc_span::def_id::{CRATE_DEF_ID, LocalDefId};
1314

@@ -185,13 +186,20 @@ impl EffectiveVisibilities {
185186
if !is_impl && tcx.trait_impl_of_assoc(def_id.to_def_id()).is_none() {
186187
let nominal_vis = tcx.visibility(def_id);
187188
if ev.reachable.greater_than(nominal_vis, tcx) {
188-
span_bug!(
189-
span,
190-
"{:?}: reachable {:?} > nominal {:?}",
191-
def_id,
192-
ev.reachable,
193-
nominal_vis,
194-
);
189+
if let Node::Item(item) = tcx.hir_node_by_def_id(def_id)
190+
&& let ItemKind::Use(_, UseKind::Glob) = item.kind
191+
{
192+
// Glob import visibilities can be increased by other
193+
// more public glob imports in cases of ambiguity.
194+
} else {
195+
span_bug!(
196+
span,
197+
"{:?}: reachable {:?} > nominal {:?}",
198+
def_id,
199+
ev.reachable,
200+
nominal_vis,
201+
);
202+
}
195203
}
196204
}
197205
}

compiler/rustc_resolve/src/build_reduced_graph.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
9393
ambiguity: CmCell::new(ambiguity),
9494
// External ambiguities always report the `AMBIGUOUS_GLOB_IMPORTS` lint at the moment.
9595
warn_ambiguity: CmCell::new(true),
96-
vis: CmCell::new(vis),
96+
initial_vis: vis,
97+
ambiguity_vis_max: CmCell::new(None),
98+
ambiguity_vis_min: CmCell::new(None),
9799
span,
98100
expansion,
99101
parent_module: Some(parent.to_module()),

compiler/rustc_resolve/src/effective_visibilities.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,10 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> {
182182
parent_id.level(),
183183
tcx,
184184
);
185+
if let Some(max_vis_decl) = decl.ambiguity_vis_max.get() {
186+
// Avoid the most visible import in an ambiguous glob set being reported as unused.
187+
self.update_import(max_vis_decl, parent_id);
188+
}
185189
}
186190

187191
fn update_def(

compiler/rustc_resolve/src/ident.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
490490
}
491491
Some(Finalize { import, .. }) => import,
492492
};
493+
this.get_mut().maybe_push_glob_vs_glob_vis_ambiguity(
494+
ident,
495+
orig_ident_span,
496+
decl,
497+
import,
498+
);
493499

494500
if let Some(&(innermost_decl, _)) = innermost_results.first() {
495501
// Found another solution, if the first one was "weak", report an error.
@@ -779,6 +785,30 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
779785
ret.map_err(ControlFlow::Continue)
780786
}
781787

788+
fn maybe_push_glob_vs_glob_vis_ambiguity(
789+
&mut self,
790+
ident: IdentKey,
791+
orig_ident_span: Span,
792+
decl: Decl<'ra>,
793+
import: Option<ImportSummary>,
794+
) {
795+
let Some(import) = import else { return };
796+
let vis1 = self.import_decl_vis(decl, import);
797+
let vis2 = self.import_decl_vis_ext(decl, import, true);
798+
if vis1 != vis2 {
799+
self.ambiguity_errors.push(AmbiguityError {
800+
kind: AmbiguityKind::GlobVsGlob,
801+
ambig_vis: Some((vis1, vis2)),
802+
ident: ident.orig(orig_ident_span),
803+
b1: decl.ambiguity_vis_max.get().unwrap_or(decl),
804+
b2: decl.ambiguity_vis_min.get().unwrap_or(decl),
805+
scope1: Scope::ModuleGlobs(decl.parent_module.unwrap(), None),
806+
scope2: Scope::ModuleGlobs(decl.parent_module.unwrap(), None),
807+
warning: Some(AmbiguityWarning::GlobImport),
808+
});
809+
}
810+
}
811+
782812
fn maybe_push_ambiguity(
783813
&mut self,
784814
ident: IdentKey,

compiler/rustc_resolve/src/imports.rs

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -370,8 +370,17 @@ fn remove_same_import<'ra>(d1: Decl<'ra>, d2: Decl<'ra>) -> (Decl<'ra>, Decl<'ra
370370

371371
impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
372372
pub(crate) fn import_decl_vis(&self, decl: Decl<'ra>, import: ImportSummary) -> Visibility {
373+
self.import_decl_vis_ext(decl, import, false)
374+
}
375+
376+
pub(crate) fn import_decl_vis_ext(
377+
&self,
378+
decl: Decl<'ra>,
379+
import: ImportSummary,
380+
min: bool,
381+
) -> Visibility {
373382
assert!(import.vis.is_accessible_from(import.nearest_parent_mod, self.tcx));
374-
let decl_vis = decl.vis();
383+
let decl_vis = if min { decl.min_vis() } else { decl.vis() };
375384
if decl_vis.partial_cmp(import.vis, self.tcx) == Some(Ordering::Less)
376385
&& decl_vis.is_accessible_from(import.nearest_parent_mod, self.tcx)
377386
&& pub_use_of_private_extern_crate_hack(import, decl).is_none()
@@ -409,7 +418,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
409418
ambiguity: CmCell::new(None),
410419
warn_ambiguity: CmCell::new(false),
411420
span: import.span,
412-
vis: CmCell::new(vis.to_def_id()),
421+
initial_vis: vis.to_def_id(),
422+
ambiguity_vis_max: CmCell::new(None),
423+
ambiguity_vis_min: CmCell::new(None),
413424
expansion: import.parent_scope.expansion,
414425
parent_module: Some(import.parent_scope.module),
415426
})
@@ -434,8 +445,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
434445
// - A glob decl is overwritten by its clone after setting ambiguity in it.
435446
// FIXME: avoid this by removing `warn_ambiguity`, or by triggering glob re-fetch
436447
// with the same decl in some way.
437-
// - A glob decl is overwritten by a glob decl with larger visibility.
438-
// FIXME: avoid this by updating this visibility in place.
439448
// - A glob decl is overwritten by a glob decl re-fetching an
440449
// overwritten decl from other module (the recursive case).
441450
// Here we are detecting all such re-fetches and overwrite old decls
@@ -449,8 +458,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
449458
// FIXME: reenable the asserts when `warn_ambiguity` is removed (#149195).
450459
// assert_ne!(old_deep_decl, deep_decl);
451460
// assert!(old_deep_decl.is_glob_import());
452-
// FIXME: reenable the assert when visibility is updated in place.
453-
// assert!(!deep_decl.is_glob_import());
461+
assert!(!deep_decl.is_glob_import());
454462
if old_glob_decl.ambiguity.get().is_some() && glob_decl.ambiguity.get().is_none() {
455463
// Do not lose glob ambiguities when re-fetching the glob.
456464
glob_decl.ambiguity.set_unchecked(old_glob_decl.ambiguity.get());
@@ -470,12 +478,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
470478
// FIXME: remove this when `warn_ambiguity` is removed (#149195).
471479
self.arenas.alloc_decl((*old_glob_decl).clone())
472480
}
473-
} else if glob_decl.vis().greater_than(old_glob_decl.vis(), self.tcx) {
474-
// We are glob-importing the same item but with greater visibility.
481+
} else if let old_vis = old_glob_decl.vis()
482+
&& let vis = glob_decl.vis()
483+
&& old_vis != vis
484+
{
485+
// We are glob-importing the same item but with a different visibility.
475486
// All visibilities here are ordered because all of them are ancestors of `module`.
476-
// FIXME: Update visibility in place, but without regressions
477-
// (#152004, #151124, #152347).
478-
glob_decl
487+
if vis.greater_than(old_vis, self.tcx) {
488+
old_glob_decl.ambiguity_vis_max.set_unchecked(Some(glob_decl));
489+
} else if let old_min_vis = old_glob_decl.min_vis()
490+
&& old_min_vis != vis
491+
&& old_min_vis.greater_than(vis, self.tcx)
492+
{
493+
old_glob_decl.ambiguity_vis_min.set_unchecked(Some(glob_decl));
494+
}
495+
old_glob_decl
479496
} else if glob_decl.is_ambiguity_recursive() && !old_glob_decl.is_ambiguity_recursive() {
480497
// Overwriting a non-ambiguous glob import with an ambiguous glob import.
481498
old_glob_decl.ambiguity.set_unchecked(Some(glob_decl));
@@ -498,6 +515,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
498515
) -> Result<(), Decl<'ra>> {
499516
assert!(!decl.warn_ambiguity.get());
500517
assert!(decl.ambiguity.get().is_none());
518+
assert!(decl.ambiguity_vis_max.get().is_none());
519+
assert!(decl.ambiguity_vis_min.get().is_none());
501520
let module = decl.parent_module.unwrap().expect_local();
502521
assert!(self.is_accessible_from(decl.vis(), module.to_module()));
503522
let res = decl.res();
@@ -556,11 +575,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
556575
.resolution_or_default(module.to_module(), key, orig_ident_span)
557576
.borrow_mut_unchecked();
558577
let old_decl = resolution.determined_decl();
578+
let old_vis = old_decl.map(|d| d.vis());
559579

560580
let t = f(self, resolution);
561581

562582
if let Some(binding) = resolution.determined_decl()
563-
&& old_decl != Some(binding)
583+
&& (old_decl != Some(binding) || old_vis != Some(binding.vis()))
564584
{
565585
(binding, t, warn_ambiguity || old_decl.is_some())
566586
} else {

compiler/rustc_resolve/src/lib.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -929,7 +929,13 @@ struct DeclData<'ra> {
929929
warn_ambiguity: CmCell<bool>,
930930
expansion: LocalExpnId,
931931
span: Span,
932-
vis: CmCell<Visibility<DefId>>,
932+
initial_vis: Visibility<DefId>,
933+
/// If the declaration refers to an ambiguous glob set, then this is the most visible
934+
/// declaration from the set, if its visibility is different from `initial_vis`.
935+
ambiguity_vis_max: CmCell<Option<Decl<'ra>>>,
936+
/// If the declaration refers to an ambiguous glob set, then this is the least visible
937+
/// declaration from the set, if its visibility is different from `initial_vis`.
938+
ambiguity_vis_min: CmCell<Option<Decl<'ra>>>,
933939
parent_module: Option<Module<'ra>>,
934940
}
935941

@@ -1049,7 +1055,13 @@ struct AmbiguityError<'ra> {
10491055

10501056
impl<'ra> DeclData<'ra> {
10511057
fn vis(&self) -> Visibility<DefId> {
1052-
self.vis.get()
1058+
// Select the maximum visibility if there are multiple ambiguous glob imports.
1059+
self.ambiguity_vis_max.get().map(|d| d.vis()).unwrap_or_else(|| self.initial_vis)
1060+
}
1061+
1062+
fn min_vis(&self) -> Visibility<DefId> {
1063+
// Select the minimum visibility if there are multiple ambiguous glob imports.
1064+
self.ambiguity_vis_min.get().map(|d| d.vis()).unwrap_or_else(|| self.initial_vis)
10531065
}
10541066

10551067
fn res(&self) -> Res {
@@ -1505,7 +1517,9 @@ impl<'ra> ResolverArenas<'ra> {
15051517
kind: DeclKind::Def(res),
15061518
ambiguity: CmCell::new(None),
15071519
warn_ambiguity: CmCell::new(false),
1508-
vis: CmCell::new(vis),
1520+
initial_vis: vis,
1521+
ambiguity_vis_max: CmCell::new(None),
1522+
ambiguity_vis_min: CmCell::new(None),
15091523
span,
15101524
expansion,
15111525
parent_module,

tests/ui/imports/ambiguous-import-visibility-globglob-priv.stderr

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ LL | use crate::both::private::S;
55
| ^ private struct import
66
|
77
note: the struct import `S` is defined here...
8-
--> $DIR/ambiguous-import-visibility-globglob-priv.rs:8:24
8+
--> $DIR/ambiguous-import-visibility-globglob-priv.rs:7:13
99
|
10-
LL | pub(super) use crate::m::*;
11-
| ^^^^^^^^^^^
10+
LL | use crate::m::*;
11+
| ^^^^^^^^^^^
1212
note: ...and refers to the struct `S` which is defined here
1313
--> $DIR/ambiguous-import-visibility-globglob-priv.rs:2:5
1414
|
@@ -27,10 +27,10 @@ LL | use crate::both::private::S;
2727
| ^ private struct import
2828
|
2929
note: the struct import `S` is defined here...
30-
--> $DIR/ambiguous-import-visibility-globglob-priv.rs:8:24
30+
--> $DIR/ambiguous-import-visibility-globglob-priv.rs:7:13
3131
|
32-
LL | pub(super) use crate::m::*;
33-
| ^^^^^^^^^^^
32+
LL | use crate::m::*;
33+
| ^^^^^^^^^^^
3434
note: ...and refers to the struct `S` which is defined here
3535
--> $DIR/ambiguous-import-visibility-globglob-priv.rs:2:5
3636
|

tests/ui/imports/ambiguous-import-visibility-globglob.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
//@ check-pass
22

3-
// FIXME: should report "ambiguous import visibility" in all the cases below.
4-
53
mod m {
64
pub struct S {}
75
}
@@ -12,7 +10,11 @@ mod min_vis_first {
1210
pub use crate::m::*;
1311

1412
pub use self::S as S1;
13+
//~^ WARN ambiguous import visibility
14+
//~| WARN this was previously accepted
1515
pub(crate) use self::S as S2;
16+
//~^ WARN ambiguous import visibility
17+
//~| WARN this was previously accepted
1618
use self::S as S3; // OK
1719
}
1820

@@ -22,7 +24,11 @@ mod mid_vis_first {
2224
pub use crate::m::*;
2325

2426
pub use self::S as S1;
27+
//~^ WARN ambiguous import visibility
28+
//~| WARN this was previously accepted
2529
pub(crate) use self::S as S2;
30+
//~^ WARN ambiguous import visibility
31+
//~| WARN this was previously accepted
2632
use self::S as S3; // OK
2733
}
2834

@@ -32,7 +38,11 @@ mod max_vis_first {
3238
pub(crate) use crate::m::*;
3339

3440
pub use self::S as S1;
41+
//~^ WARN ambiguous import visibility
42+
//~| WARN this was previously accepted
3543
pub(crate) use self::S as S2;
44+
//~^ WARN ambiguous import visibility
45+
//~| WARN this was previously accepted
3646
use self::S as S3; // OK
3747
}
3848

0 commit comments

Comments
 (0)