Skip to content

Commit fca6a56

Browse files
committed
Prefer pub(super) in unreachable_pub lint suggestion
1 parent b5f4883 commit fca6a56

File tree

7 files changed

+345
-30
lines changed

7 files changed

+345
-30
lines changed

compiler/rustc_lint/src/builtin.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1295,15 +1295,57 @@ impl UnreachablePub {
12951295
vis_span: Span,
12961296
exportable: bool,
12971297
) {
1298+
fn opt_parent_module(tcx: TyCtxt<'_>, mut did: LocalDefId) -> Option<LocalDefId> {
1299+
while let Some(parent) = tcx.opt_local_parent(did) {
1300+
did = parent;
1301+
if tcx.def_kind(did) == DefKind::Mod {
1302+
return Some(did);
1303+
}
1304+
}
1305+
None
1306+
}
1307+
12981308
let mut applicability = Applicability::MachineApplicable;
12991309
if cx.tcx.visibility(def_id).is_public() && !cx.effective_visibilities.is_reachable(def_id)
13001310
{
1311+
// prefer suggesting `pub(super)` instead of `pub(crate)` when possible
1312+
let new_vis = if let Some(reachable_vis) =
1313+
cx.effective_visibilities.effective_vis(def_id).map(|effective_vis| {
1314+
effective_vis.at_level(rustc_middle::middle::privacy::Level::Reachable)
1315+
}) {
1316+
let rustc_middle::ty::Visibility::Restricted(restricted_id) = reachable_vis else {
1317+
unreachable!()
1318+
};
1319+
1320+
if let Some(parent) = opt_parent_module(cx.tcx, def_id.into()) {
1321+
if let Some(parent_parent) = opt_parent_module(cx.tcx, parent) {
1322+
if &parent_parent == restricted_id {
1323+
// current item is restricted to the parent of it's parent (aka super)
1324+
"pub(super)"
1325+
} else {
1326+
// current item is not restricted to the parent of it's parent
1327+
"pub(crate)"
1328+
}
1329+
} else {
1330+
// unreachable pub at crate root, is that even possible?
1331+
"pub(crate)"
1332+
}
1333+
} else {
1334+
// current item has no parent, is that even possible?
1335+
"pub(crate)"
1336+
}
1337+
} else {
1338+
// current item can't be reach from crate, probably in an anon-const
1339+
"pub(crate)"
1340+
};
1341+
13011342
if vis_span.from_expansion() {
13021343
applicability = Applicability::MaybeIncorrect;
13031344
}
13041345
let def_span = cx.tcx.def_span(def_id);
13051346
cx.emit_span_lint(UNREACHABLE_PUB, def_span, BuiltinUnreachablePub {
13061347
what,
1348+
new_vis,
13071349
suggestion: (vis_span, applicability),
13081350
help: exportable,
13091351
});

compiler/rustc_lint/src/lints.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,8 @@ impl<'a> LintDiagnostic<'a, ()> for BuiltinUngatedAsyncFnTrackCaller<'_> {
254254
#[diag(lint_builtin_unreachable_pub)]
255255
pub(crate) struct BuiltinUnreachablePub<'a> {
256256
pub what: &'a str,
257-
#[suggestion(code = "pub(crate)")]
257+
pub new_vis: &'a str,
258+
#[suggestion(code = "{new_vis}")]
258259
pub suggestion: (Span, Applicability),
259260
#[help]
260261
pub help: bool,

tests/ui/lint/issue-103317.fixed

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#[warn(unreachable_pub)]
55
mod inner {
66
#[allow(unused)]
7-
pub(crate) enum T {
7+
pub(super) enum T {
88
//~^ WARN unreachable `pub` item
99
A(u8),
1010
X { a: f32, b: () },

tests/ui/lint/issue-103317.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ warning: unreachable `pub` item
44
LL | pub enum T {
55
| ---^^^^^^^
66
| |
7-
| help: consider restricting its visibility: `pub(crate)`
7+
| help: consider restricting its visibility: `pub(super)`
88
|
99
= help: or consider exporting it for use by other crates
1010
note: the lint level is defined here

tests/ui/lint/unreachable_pub.fixed

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
//@ check-pass
2+
//@ edition: 2018
3+
//@ run-rustfix
4+
5+
#![allow(unused)]
6+
#![warn(unreachable_pub)]
7+
8+
mod private_mod {
9+
// non-leaked `pub` items in private module should be linted
10+
pub(super) use std::fmt; //~ WARNING unreachable_pub
11+
pub(super) use std::env::{Args}; // braced-use has different item spans than unbraced
12+
//~^ WARNING unreachable_pub
13+
14+
// we lint on struct definition
15+
pub(super) struct Hydrogen { //~ WARNING unreachable_pub
16+
// but not on fields, even if they are `pub` as putting `pub(crate)`
17+
// it would clutter the source code for little value
18+
pub neutrons: usize,
19+
pub(crate) electrons: usize
20+
}
21+
pub(crate) struct Calcium {
22+
pub neutrons: usize,
23+
}
24+
impl Hydrogen {
25+
// impls, too
26+
pub(super) fn count_neutrons(&self) -> usize { self.neutrons } //~ WARNING unreachable_pub
27+
pub(crate) fn count_electrons(&self) -> usize { self.electrons }
28+
}
29+
impl Clone for Hydrogen {
30+
fn clone(&self) -> Hydrogen {
31+
Hydrogen { neutrons: self.neutrons, electrons: self.electrons }
32+
}
33+
}
34+
35+
pub(super) enum Helium {} //~ WARNING unreachable_pub
36+
pub(super) union Lithium { c1: usize, c2: u8 } //~ WARNING unreachable_pub
37+
pub(super) fn beryllium() {} //~ WARNING unreachable_pub
38+
pub(super) trait Boron {} //~ WARNING unreachable_pub
39+
pub(super) const CARBON: usize = 1; //~ WARNING unreachable_pub
40+
pub(super) static NITROGEN: usize = 2; //~ WARNING unreachable_pub
41+
pub(super) type Oxygen = bool; //~ WARNING unreachable_pub
42+
43+
macro_rules! define_empty_struct_with_visibility {
44+
($visibility: vis, $name: ident) => { $visibility struct $name {} }
45+
//~^ WARNING unreachable_pub
46+
}
47+
define_empty_struct_with_visibility!(pub(super), Fluorine);
48+
49+
extern "C" {
50+
pub(super) fn catalyze() -> bool; //~ WARNING unreachable_pub
51+
}
52+
53+
mod private_in_private {
54+
pub(super) enum Helium {} //~ WARNING unreachable_pub
55+
pub(super) fn beryllium() {} //~ WARNING unreachable_pub
56+
}
57+
58+
pub(crate) mod crate_in_private {
59+
pub(crate) const CARBON: usize = 1; //~ WARNING unreachable_pub
60+
}
61+
62+
pub(super) mod pub_in_private { //~ WARNING unreachable_pub
63+
pub(crate) static NITROGEN: usize = 2; //~ WARNING unreachable_pub
64+
}
65+
66+
fn foo() {
67+
const {
68+
pub(crate) struct Foo; //~ WARNING unreachable_pub
69+
};
70+
}
71+
72+
enum Weird {
73+
Variant = {
74+
pub(crate) struct Foo; //~ WARNING unreachable_pub
75+
76+
mod tmp {
77+
pub(crate) struct Bar; //~ WARNING unreachable_pub
78+
}
79+
80+
let _ = tmp::Bar;
81+
82+
0
83+
},
84+
}
85+
86+
pub(super) use fpu_precision::set_precision; //~ WARNING unreachable_pub
87+
88+
mod fpu_precision {
89+
pub(crate) fn set_precision<T>() {} //~ WARNING unreachable_pub
90+
pub(super) fn set_micro_precision<T>() {} //~ WARNING unreachable_pub
91+
}
92+
93+
// items leaked through signatures (see `get_neon` below) are OK
94+
pub struct Neon {}
95+
96+
// crate-visible items are OK
97+
pub(crate) struct Sodium {}
98+
}
99+
100+
pub mod public_mod {
101+
// module is public: these are OK, too
102+
pub struct Magnesium {}
103+
pub(crate) struct Aluminum {}
104+
}
105+
106+
pub fn get_neon() -> private_mod::Neon {
107+
private_mod::Neon {}
108+
}
109+
110+
fn main() {
111+
let _ = get_neon();
112+
let _ = private_mod::beryllium();
113+
let _ = private_mod::crate_in_private::CARBON;
114+
let _ = private_mod::pub_in_private::NITROGEN;
115+
let _ = unsafe { private_mod::catalyze() };
116+
}

tests/ui/lint/unreachable_pub.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
//@ check-pass
2+
//@ edition: 2018
3+
//@ run-rustfix
24

35
#![allow(unused)]
46
#![warn(unreachable_pub)]
@@ -48,6 +50,46 @@ mod private_mod {
4850
pub fn catalyze() -> bool; //~ WARNING unreachable_pub
4951
}
5052

53+
mod private_in_private {
54+
pub enum Helium {} //~ WARNING unreachable_pub
55+
pub fn beryllium() {} //~ WARNING unreachable_pub
56+
}
57+
58+
pub(crate) mod crate_in_private {
59+
pub const CARBON: usize = 1; //~ WARNING unreachable_pub
60+
}
61+
62+
pub mod pub_in_private { //~ WARNING unreachable_pub
63+
pub static NITROGEN: usize = 2; //~ WARNING unreachable_pub
64+
}
65+
66+
fn foo() {
67+
const {
68+
pub struct Foo; //~ WARNING unreachable_pub
69+
};
70+
}
71+
72+
enum Weird {
73+
Variant = {
74+
pub struct Foo; //~ WARNING unreachable_pub
75+
76+
mod tmp {
77+
pub struct Bar; //~ WARNING unreachable_pub
78+
}
79+
80+
let _ = tmp::Bar;
81+
82+
0
83+
},
84+
}
85+
86+
pub use fpu_precision::set_precision; //~ WARNING unreachable_pub
87+
88+
mod fpu_precision {
89+
pub fn set_precision<T>() {} //~ WARNING unreachable_pub
90+
pub fn set_micro_precision<T>() {} //~ WARNING unreachable_pub
91+
}
92+
5193
// items leaked through signatures (see `get_neon` below) are OK
5294
pub struct Neon {}
5395

@@ -67,4 +109,8 @@ pub fn get_neon() -> private_mod::Neon {
67109

68110
fn main() {
69111
let _ = get_neon();
112+
let _ = private_mod::beryllium();
113+
let _ = private_mod::crate_in_private::CARBON;
114+
let _ = private_mod::pub_in_private::NITROGEN;
115+
let _ = unsafe { private_mod::catalyze() };
70116
}

0 commit comments

Comments
 (0)