From 5885285b2981d6d387b286911162cd4f158f0023 Mon Sep 17 00:00:00 2001 From: mu001999 Date: Mon, 1 Dec 2025 23:41:31 +0800 Subject: [PATCH 1/2] Add new unstable flag -Ztreat-pub-as-pub-crate --- compiler/rustc_passes/src/dead.rs | 33 ++++++++++--------- compiler/rustc_session/src/options.rs | 2 ++ .../dead-code/treat-pub-as-pub-crate-lib.rs | 8 +++++ .../treat-pub-as-pub-crate-lib.stderr | 14 ++++++++ .../lint/dead-code/treat-pub-as-pub-crate.rs | 11 +++++++ .../dead-code/treat-pub-as-pub-crate.stderr | 14 ++++++++ 6 files changed, 67 insertions(+), 15 deletions(-) create mode 100644 tests/ui/lint/dead-code/treat-pub-as-pub-crate-lib.rs create mode 100644 tests/ui/lint/dead-code/treat-pub-as-pub-crate-lib.stderr create mode 100644 tests/ui/lint/dead-code/treat-pub-as-pub-crate.rs create mode 100644 tests/ui/lint/dead-code/treat-pub-as-pub-crate.stderr diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 705d1b9e38408..1c155b837ac6b 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -19,6 +19,7 @@ use rustc_middle::middle::privacy::Level; use rustc_middle::query::Providers; use rustc_middle::ty::{self, AssocTag, TyCtxt}; use rustc_middle::{bug, span_bug}; +use rustc_session::config::CrateType; use rustc_session::lint::builtin::DEAD_CODE; use rustc_session::lint::{self, LintExpectationId}; use rustc_span::{Symbol, kw, sym}; @@ -813,22 +814,24 @@ fn maybe_record_as_seed<'tcx>( fn create_and_seed_worklist( tcx: TyCtxt<'_>, ) -> (Vec<(LocalDefId, ComesFromAllowExpect)>, Vec) { - let effective_visibilities = &tcx.effective_visibilities(()); let mut unsolved_impl_item = Vec::new(); - let mut worklist = effective_visibilities - .iter() - .filter_map(|(&id, effective_vis)| { - effective_vis - .is_public_at_level(Level::Reachable) - .then_some(id) - .map(|id| (id, ComesFromAllowExpect::No)) - }) - // Seed entry point - .chain( - tcx.entry_fn(()) - .and_then(|(def_id, _)| def_id.as_local().map(|id| (id, ComesFromAllowExpect::No))), - ) - .collect::>(); + let mut worklist = Vec::new(); + + if let Some((def_id, _)) = tcx.entry_fn(()) + && let Some(local_def_id) = def_id.as_local() + { + worklist.push((local_def_id, ComesFromAllowExpect::No)); + } + + if !tcx.sess.opts.unstable_opts.treat_pub_as_pub_crate + || !tcx.crate_types().contains(&CrateType::Executable) + { + for (id, effective_vis) in tcx.effective_visibilities(()).iter() { + if effective_vis.is_public_at_level(Level::Reachable) { + worklist.push((*id, ComesFromAllowExpect::No)); + } + } + } let crate_items = tcx.hir_crate_items(()); for id in crate_items.owners() { diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 7c7e9118d590f..0c8d5a2327a4d 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2727,6 +2727,8 @@ written to standard error output)"), treat_err_as_bug: Option> = (None, parse_treat_err_as_bug, [TRACKED], "treat the `val`th error that occurs as bug (default if not specified: 0 - don't treat errors as bugs. \ default if specified without a value: 1 - treat the first error as bug)"), + treat_pub_as_pub_crate: bool = (false, parse_bool, [UNTRACKED], + "treat `pub` items as `pub(crate)` items for binary crates (default: no)"), trim_diagnostic_paths: bool = (true, parse_bool, [UNTRACKED], "in diagnostics, use heuristics to shorten paths referring to items"), tune_cpu: Option = (None, parse_opt_string, [TRACKED], diff --git a/tests/ui/lint/dead-code/treat-pub-as-pub-crate-lib.rs b/tests/ui/lint/dead-code/treat-pub-as-pub-crate-lib.rs new file mode 100644 index 0000000000000..5e5b62c4035ae --- /dev/null +++ b/tests/ui/lint/dead-code/treat-pub-as-pub-crate-lib.rs @@ -0,0 +1,8 @@ +//@ compile-flags: -Ztreat-pub-as-pub-crate +#![feature(rustc_attrs)] +#![deny(dead_code)] +#![crate_type = "lib"] + +pub fn unused_pub_fn() {} // Should NOT error because it's a library crate + +fn unused_priv_fn() {} //~ ERROR function `unused_priv_fn` is never used diff --git a/tests/ui/lint/dead-code/treat-pub-as-pub-crate-lib.stderr b/tests/ui/lint/dead-code/treat-pub-as-pub-crate-lib.stderr new file mode 100644 index 0000000000000..f23b264dd7e58 --- /dev/null +++ b/tests/ui/lint/dead-code/treat-pub-as-pub-crate-lib.stderr @@ -0,0 +1,14 @@ +error: function `unused_priv_fn` is never used + --> $DIR/treat-pub-as-pub-crate-lib.rs:8:4 + | +LL | fn unused_priv_fn() {} + | ^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/treat-pub-as-pub-crate-lib.rs:3:9 + | +LL | #![deny(dead_code)] + | ^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/lint/dead-code/treat-pub-as-pub-crate.rs b/tests/ui/lint/dead-code/treat-pub-as-pub-crate.rs new file mode 100644 index 0000000000000..e7a0f6845acaa --- /dev/null +++ b/tests/ui/lint/dead-code/treat-pub-as-pub-crate.rs @@ -0,0 +1,11 @@ +//@ compile-flags: -Ztreat-pub-as-pub-crate +#![feature(rustc_attrs)] +#![deny(dead_code)] + +pub fn unused_pub_fn() {} //~ ERROR function `unused_pub_fn` is never used + +pub fn used_pub_fn() {} + +fn main() { + used_pub_fn(); +} diff --git a/tests/ui/lint/dead-code/treat-pub-as-pub-crate.stderr b/tests/ui/lint/dead-code/treat-pub-as-pub-crate.stderr new file mode 100644 index 0000000000000..6a7f45496196f --- /dev/null +++ b/tests/ui/lint/dead-code/treat-pub-as-pub-crate.stderr @@ -0,0 +1,14 @@ +error: function `unused_pub_fn` is never used + --> $DIR/treat-pub-as-pub-crate.rs:5:8 + | +LL | pub fn unused_pub_fn() {} + | ^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/treat-pub-as-pub-crate.rs:3:9 + | +LL | #![deny(dead_code)] + | ^^^^^^^^^ + +error: aborting due to 1 previous error + From 8ac52ba4a3e01ea0d3301875afc4caa125801b4f Mon Sep 17 00:00:00 2001 From: mu001999 Date: Tue, 2 Dec 2025 10:00:05 +0800 Subject: [PATCH 2/2] Document -Ztreat-pub-as-pub-crate --- .../compiler-flags/treat-pub-as-pub-crate.md | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/doc/unstable-book/src/compiler-flags/treat-pub-as-pub-crate.md diff --git a/src/doc/unstable-book/src/compiler-flags/treat-pub-as-pub-crate.md b/src/doc/unstable-book/src/compiler-flags/treat-pub-as-pub-crate.md new file mode 100644 index 0000000000000..60af59ad9d3f4 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/treat-pub-as-pub-crate.md @@ -0,0 +1,31 @@ +# `treat-pub-as-pub-crate` + +The `-Ztreat-pub-as-pub-crate` flag causes the compiler to treat all `pub` items in the crate as if they were `pub(crate)`. This is useful for finding dead code in binary crates where public items are not intended to be exported to other crates. + +When this flag is enabled, the dead code lint will warn about public items that are not used within the crate (unless they are the entry point, like `main`). + +## Example + +Consider the following code in a binary crate: + +```rust +pub fn unused_pub_fn() {} + +fn main() { + println!("Hello, world!"); +} +``` + +By default, `rustc` assumes that `unused_pub_fn` might be used by other crates linking to this binary, so it does not warn about it being unused. + +With `-Ztreat-pub-as-pub-crate`, `rustc` will emit a warning: + +```text +warning: function `unused_pub_fn` is never used + --> src/main.rs:1:8 + | +1 | pub fn unused_pub_fn() {} + | ^^^^^^^^^^^^^ + | + = note: `#[warn(dead_code)]` on by default +```