Make dead code check a query.
This commit is contained in:
parent
312a7995e7
commit
4e7d47bb6c
5 changed files with 62 additions and 33 deletions
|
@ -999,7 +999,8 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
|
||||||
tcx.ensure().check_private_in_public(());
|
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", || {
|
sess.time("unused_lib_feature_checking", || {
|
||||||
|
|
|
@ -750,6 +750,22 @@ rustc_queries! {
|
||||||
desc { |tcx| "checking liveness of variables in {}", describe_as_module(key, tcx) }
|
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) -> () {
|
query check_mod_impl_wf(key: LocalDefId) -> () {
|
||||||
desc { |tcx| "checking that impls are well-formed in {}", describe_as_module(key, tcx) }
|
desc { |tcx| "checking that impls are well-formed in {}", describe_as_module(key, tcx) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ use rustc_hir::{Node, PatKind, TyKind};
|
||||||
use rustc_middle::hir::nested_filter;
|
use rustc_middle::hir::nested_filter;
|
||||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||||
use rustc_middle::middle::privacy;
|
use rustc_middle::middle::privacy;
|
||||||
|
use rustc_middle::ty::query::Providers;
|
||||||
use rustc_middle::ty::{self, DefIdTree, TyCtxt};
|
use rustc_middle::ty::{self, DefIdTree, TyCtxt};
|
||||||
use rustc_session::lint;
|
use rustc_session::lint;
|
||||||
use rustc_span::symbol::{sym, Symbol};
|
use rustc_span::symbol::{sym, Symbol};
|
||||||
|
@ -52,7 +53,7 @@ struct MarkSymbolVisitor<'tcx> {
|
||||||
// maps from ADTs to ignored derived traits (e.g. Debug and Clone)
|
// 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
|
// and the span of their respective impl (i.e., part of the derive
|
||||||
// macro)
|
// macro)
|
||||||
ignored_derived_traits: FxHashMap<DefId, Vec<(Span, DefId)>>,
|
ignored_derived_traits: FxHashMap<LocalDefId, Vec<(DefId, DefId)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> MarkSymbolVisitor<'tcx> {
|
impl<'tcx> MarkSymbolVisitor<'tcx> {
|
||||||
|
@ -258,12 +259,11 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
|
||||||
if self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads) {
|
if self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads) {
|
||||||
let trait_ref = self.tcx.impl_trait_ref(impl_of).unwrap();
|
let trait_ref = self.tcx.impl_trait_ref(impl_of).unwrap();
|
||||||
if let ty::Adt(adt_def, _) = trait_ref.self_ty().kind() {
|
if let ty::Adt(adt_def, _) = trait_ref.self_ty().kind() {
|
||||||
let impl_span = self.tcx.def_span(impl_of);
|
if let Some(adt_def_id) = adt_def.did.as_local() {
|
||||||
if let Some(v) = self.ignored_derived_traits.get_mut(&adt_def.did) {
|
|
||||||
v.push((impl_span, trait_of));
|
|
||||||
} else {
|
|
||||||
self.ignored_derived_traits
|
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;
|
return true;
|
||||||
|
@ -563,8 +563,8 @@ impl<'v, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'tcx> {
|
||||||
|
|
||||||
fn create_and_seed_worklist<'tcx>(
|
fn create_and_seed_worklist<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
access_levels: &privacy::AccessLevels,
|
|
||||||
) -> (Vec<LocalDefId>, FxHashMap<LocalDefId, LocalDefId>) {
|
) -> (Vec<LocalDefId>, FxHashMap<LocalDefId, LocalDefId>) {
|
||||||
|
let access_levels = &tcx.privacy_access_levels(());
|
||||||
let worklist = access_levels
|
let worklist = access_levels
|
||||||
.map
|
.map
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -584,11 +584,11 @@ fn create_and_seed_worklist<'tcx>(
|
||||||
(life_seeder.worklist, life_seeder.struct_constructors)
|
(life_seeder.worklist, life_seeder.struct_constructors)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_live<'tcx>(
|
fn live_symbols_and_ignored_derived_traits<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
access_levels: &privacy::AccessLevels,
|
(): (),
|
||||||
) -> (FxHashSet<LocalDefId>, FxHashMap<DefId, Vec<(Span, DefId)>>) {
|
) -> (FxHashSet<LocalDefId>, FxHashMap<LocalDefId, Vec<(DefId, DefId)>>) {
|
||||||
let (worklist, struct_constructors) = create_and_seed_worklist(tcx, access_levels);
|
let (worklist, struct_constructors) = create_and_seed_worklist(tcx);
|
||||||
let mut symbol_visitor = MarkSymbolVisitor {
|
let mut symbol_visitor = MarkSymbolVisitor {
|
||||||
worklist,
|
worklist,
|
||||||
tcx,
|
tcx,
|
||||||
|
@ -608,8 +608,8 @@ fn find_live<'tcx>(
|
||||||
|
|
||||||
struct DeadVisitor<'tcx> {
|
struct DeadVisitor<'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
live_symbols: FxHashSet<LocalDefId>,
|
live_symbols: &'tcx FxHashSet<LocalDefId>,
|
||||||
ignored_derived_traits: FxHashMap<DefId, Vec<(Span, DefId)>>,
|
ignored_derived_traits: &'tcx FxHashMap<LocalDefId, Vec<(DefId, DefId)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> DeadVisitor<'tcx> {
|
impl<'tcx> DeadVisitor<'tcx> {
|
||||||
|
@ -682,12 +682,10 @@ impl<'tcx> DeadVisitor<'tcx> {
|
||||||
let hir = self.tcx.hir();
|
let hir = self.tcx.hir();
|
||||||
if let Some(encl_scope) = hir.get_enclosing_scope(id) {
|
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(encl_def_id) = hir.opt_local_def_id(encl_scope) {
|
||||||
if let Some(ign_traits) =
|
if let Some(ign_traits) = self.ignored_derived_traits.get(&encl_def_id) {
|
||||||
self.ignored_derived_traits.get(&encl_def_id.to_def_id())
|
|
||||||
{
|
|
||||||
let traits_str = ign_traits
|
let traits_str = ign_traits
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(_, t)| format!("`{}`", self.tcx.item_name(*t)))
|
.map(|(trait_id, _)| format!("`{}`", self.tcx.item_name(*trait_id)))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(" and ");
|
.join(" and ");
|
||||||
let plural_s = pluralize!(ign_traits.len());
|
let plural_s = pluralize!(ign_traits.len());
|
||||||
|
@ -703,7 +701,10 @@ impl<'tcx> DeadVisitor<'tcx> {
|
||||||
traits_str,
|
traits_str,
|
||||||
is_are
|
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);
|
err.span_note(multispan, &msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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(
|
fn visit_variant(
|
||||||
&mut self,
|
&mut self,
|
||||||
variant: &'tcx hir::Variant<'tcx>,
|
variant: &'tcx hir::Variant<'tcx>,
|
||||||
|
@ -836,9 +840,16 @@ impl<'tcx> Visitor<'tcx> for DeadVisitor<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_crate(tcx: TyCtxt<'_>) {
|
fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalDefId) {
|
||||||
let access_levels = &tcx.privacy_access_levels(());
|
let (live_symbols, ignored_derived_traits) = tcx.live_symbols_and_ignored_derived_traits(());
|
||||||
let (live_symbols, ignored_derived_traits) = find_live(tcx, access_levels);
|
|
||||||
let mut visitor = DeadVisitor { tcx, live_symbols, 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 };
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ mod weak_lang_items;
|
||||||
pub fn provide(providers: &mut Providers) {
|
pub fn provide(providers: &mut Providers) {
|
||||||
check_attr::provide(providers);
|
check_attr::provide(providers);
|
||||||
check_const::provide(providers);
|
check_const::provide(providers);
|
||||||
|
dead::provide(providers);
|
||||||
diagnostic_items::provide(providers);
|
diagnostic_items::provide(providers);
|
||||||
entry::provide(providers);
|
entry::provide(providers);
|
||||||
lang_items::provide(providers);
|
lang_items::provide(providers);
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error: struct is never constructed: `Bar`
|
error: static is never used: `priv_static`
|
||||||
--> $DIR/lint-dead-code-1.rs:12:16
|
--> $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
|
note: the lint level is defined here
|
||||||
--> $DIR/lint-dead-code-1.rs:5:9
|
--> $DIR/lint-dead-code-1.rs:5:9
|
||||||
|
@ -10,12 +10,6 @@ note: the lint level is defined here
|
||||||
LL | #![deny(dead_code)]
|
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`
|
error: constant is never used: `priv_const`
|
||||||
--> $DIR/lint-dead-code-1.rs:27:1
|
--> $DIR/lint-dead-code-1.rs:27:1
|
||||||
|
|
|
|
||||||
|
@ -64,5 +58,11 @@ error: function is never used: `baz`
|
||||||
LL | fn baz() -> impl Copy {
|
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
|
error: aborting due to 10 previous errors
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue