Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make dead code check a query. #93466

Merged
merged 1 commit into from
Feb 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion compiler/rustc_interface/src/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -999,7 +999,8 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
tcx.ensure().check_private_in_public(());
},
{
sess.time("death_checking", || rustc_passes::dead::check_crate(tcx));
tcx.hir()
.par_for_each_module(|module| tcx.ensure().check_mod_deathness(module));
},
{
sess.time("unused_lib_feature_checking", || {
Expand Down
16 changes: 16 additions & 0 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,22 @@ rustc_queries! {
desc { |tcx| "checking liveness of variables in {}", describe_as_module(key, tcx) }
}

/// Return the live symbols in the crate for dead code check.
///
/// The second return value maps from ADTs to ignored derived traits (e.g. Debug and Clone) and
/// their respective impl (i.e., part of the derive macro)
query live_symbols_and_ignored_derived_traits(_: ()) -> (
FxHashSet<LocalDefId>,
FxHashMap<LocalDefId, Vec<(DefId, DefId)>>
) {
storage(ArenaCacheSelector<'tcx>)
desc { "find live symbols in crate" }
}

query check_mod_deathness(key: LocalDefId) -> () {
desc { |tcx| "checking deathness of variables in {}", describe_as_module(key, tcx) }
}

query check_mod_impl_wf(key: LocalDefId) -> () {
desc { |tcx| "checking that impls are well-formed in {}", describe_as_module(key, tcx) }
}
Expand Down
55 changes: 33 additions & 22 deletions compiler/rustc_passes/src/dead.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use rustc_hir::{Node, PatKind, TyKind};
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::middle::privacy;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, DefIdTree, TyCtxt};
use rustc_session::lint;
use rustc_span::symbol::{sym, Symbol};
Expand Down Expand Up @@ -52,7 +53,7 @@ struct MarkSymbolVisitor<'tcx> {
// maps from ADTs to ignored derived traits (e.g. Debug and Clone)
// and the span of their respective impl (i.e., part of the derive
// macro)
ignored_derived_traits: FxHashMap<DefId, Vec<(Span, DefId)>>,
ignored_derived_traits: FxHashMap<LocalDefId, Vec<(DefId, DefId)>>,
}

impl<'tcx> MarkSymbolVisitor<'tcx> {
Expand Down Expand Up @@ -258,12 +259,11 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
if self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads) {
let trait_ref = self.tcx.impl_trait_ref(impl_of).unwrap();
if let ty::Adt(adt_def, _) = trait_ref.self_ty().kind() {
let impl_span = self.tcx.def_span(impl_of);
if let Some(v) = self.ignored_derived_traits.get_mut(&adt_def.did) {
v.push((impl_span, trait_of));
} else {
if let Some(adt_def_id) = adt_def.did.as_local() {
self.ignored_derived_traits
.insert(adt_def.did, vec![(impl_span, trait_of)]);
.entry(adt_def_id)
.or_default()
.push((trait_of, impl_of));
}
}
return true;
Expand Down Expand Up @@ -563,8 +563,8 @@ impl<'v, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'tcx> {

fn create_and_seed_worklist<'tcx>(
tcx: TyCtxt<'tcx>,
access_levels: &privacy::AccessLevels,
) -> (Vec<LocalDefId>, FxHashMap<LocalDefId, LocalDefId>) {
let access_levels = &tcx.privacy_access_levels(());
let worklist = access_levels
.map
.iter()
Expand All @@ -584,11 +584,11 @@ fn create_and_seed_worklist<'tcx>(
(life_seeder.worklist, life_seeder.struct_constructors)
}

fn find_live<'tcx>(
fn live_symbols_and_ignored_derived_traits<'tcx>(
tcx: TyCtxt<'tcx>,
access_levels: &privacy::AccessLevels,
) -> (FxHashSet<LocalDefId>, FxHashMap<DefId, Vec<(Span, DefId)>>) {
let (worklist, struct_constructors) = create_and_seed_worklist(tcx, access_levels);
(): (),
) -> (FxHashSet<LocalDefId>, FxHashMap<LocalDefId, Vec<(DefId, DefId)>>) {
let (worklist, struct_constructors) = create_and_seed_worklist(tcx);
let mut symbol_visitor = MarkSymbolVisitor {
worklist,
tcx,
Expand All @@ -608,8 +608,8 @@ fn find_live<'tcx>(

struct DeadVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
live_symbols: FxHashSet<LocalDefId>,
ignored_derived_traits: FxHashMap<DefId, Vec<(Span, DefId)>>,
live_symbols: &'tcx FxHashSet<LocalDefId>,
ignored_derived_traits: &'tcx FxHashMap<LocalDefId, Vec<(DefId, DefId)>>,
}

impl<'tcx> DeadVisitor<'tcx> {
Expand Down Expand Up @@ -682,12 +682,10 @@ impl<'tcx> DeadVisitor<'tcx> {
let hir = self.tcx.hir();
if let Some(encl_scope) = hir.get_enclosing_scope(id) {
if let Some(encl_def_id) = hir.opt_local_def_id(encl_scope) {
if let Some(ign_traits) =
self.ignored_derived_traits.get(&encl_def_id.to_def_id())
{
if let Some(ign_traits) = self.ignored_derived_traits.get(&encl_def_id) {
let traits_str = ign_traits
.iter()
.map(|(_, t)| format!("`{}`", self.tcx.item_name(*t)))
.map(|(trait_id, _)| format!("`{}`", self.tcx.item_name(*trait_id)))
.collect::<Vec<_>>()
.join(" and ");
let plural_s = pluralize!(ign_traits.len());
Expand All @@ -703,7 +701,10 @@ impl<'tcx> DeadVisitor<'tcx> {
traits_str,
is_are
);
let multispan = ign_traits.iter().map(|(s, _)| *s).collect::<Vec<_>>();
let multispan = ign_traits
.iter()
.map(|(_, impl_id)| self.tcx.def_span(*impl_id))
.collect::<Vec<_>>();
err.span_note(multispan, &msg);
}
}
Expand Down Expand Up @@ -761,6 +762,9 @@ impl<'tcx> Visitor<'tcx> for DeadVisitor<'tcx> {
}
}

// This visitor should only visit a single module at a time.
fn visit_mod(&mut self, _: &'tcx hir::Mod<'tcx>, _: Span, _: hir::HirId) {}

fn visit_variant(
&mut self,
variant: &'tcx hir::Variant<'tcx>,
Expand Down Expand Up @@ -836,9 +840,16 @@ impl<'tcx> Visitor<'tcx> for DeadVisitor<'tcx> {
}
}

pub fn check_crate(tcx: TyCtxt<'_>) {
let access_levels = &tcx.privacy_access_levels(());
let (live_symbols, ignored_derived_traits) = find_live(tcx, access_levels);
fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalDefId) {
let (live_symbols, ignored_derived_traits) = tcx.live_symbols_and_ignored_derived_traits(());
let mut visitor = DeadVisitor { tcx, live_symbols, ignored_derived_traits };
tcx.hir().walk_toplevel_module(&mut visitor);
let (module, _, module_id) = tcx.hir().get_module(module);
// Do not use an ItemLikeVisitor since we may want to skip visiting some items
// when a surrounding one is warned against or `_`.
intravisit::walk_mod(&mut visitor, module, module_id);
}

pub(crate) fn provide(providers: &mut Providers) {
*providers =
Providers { live_symbols_and_ignored_derived_traits, check_mod_deathness, ..*providers };
}
1 change: 1 addition & 0 deletions compiler/rustc_passes/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ mod weak_lang_items;
pub fn provide(providers: &mut Providers) {
check_attr::provide(providers);
check_const::provide(providers);
dead::provide(providers);
diagnostic_items::provide(providers);
entry::provide(providers);
lang_items::provide(providers);
Expand Down
20 changes: 10 additions & 10 deletions src/test/ui/lint/dead-code/lint-dead-code-1.stderr
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
error: struct is never constructed: `Bar`
--> $DIR/lint-dead-code-1.rs:12:16
error: static is never used: `priv_static`
--> $DIR/lint-dead-code-1.rs:20:1
|
LL | pub struct Bar;
| ^^^
LL | static priv_static: isize = 0;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: the lint level is defined here
--> $DIR/lint-dead-code-1.rs:5:9
|
LL | #![deny(dead_code)]
| ^^^^^^^^^

error: static is never used: `priv_static`
--> $DIR/lint-dead-code-1.rs:20:1
|
LL | static priv_static: isize = 0;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: constant is never used: `priv_const`
--> $DIR/lint-dead-code-1.rs:27:1
|
Expand Down Expand Up @@ -64,5 +58,11 @@ error: function is never used: `baz`
LL | fn baz() -> impl Copy {
| ^^^

error: struct is never constructed: `Bar`
--> $DIR/lint-dead-code-1.rs:12:16
|
LL | pub struct Bar;
| ^^^

error: aborting due to 10 previous errors