Skip to content

Commit 6dfcb9d

Browse files
Rollup merge of rust-lang#154149 - petrochenkov:globvisglob, r=mu001999
resolve: Extend `ambiguous_import_visibilities` deprecation lint to glob-vs-glob ambiguities Continuation of rust-lang#149596, implementation of this comment rust-lang#149596 (comment) in particular. FCP for the lint in general - rust-lang#149596 (comment). rust-lang#152498 is reverted as a part of the change, but fixes are applied to keep the tests added in that PR working. To implement this we have to have to track the most and the least visible declarations in an ambiguous glob set. Part of rust-lang#153961. r? @yaahc maybe
2 parents c935696 + d28ea81 commit 6dfcb9d

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)