about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCamille GILLOT <gillot.camille@gmail.com>2022-01-29 21:10:41 +0100
committerCamille GILLOT <gillot.camille@gmail.com>2022-02-01 13:11:03 +0100
commit4e7d47bb6c91f6db5d043a152d11ab7528266d25 (patch)
tree6b2e6ee3b86790ba76e3c98fceb366e91c5dc4f6
parent312a7995e73e390646bc61920ffead7a640addc6 (diff)
downloadrust-4e7d47bb6c91f6db5d043a152d11ab7528266d25.tar.gz
rust-4e7d47bb6c91f6db5d043a152d11ab7528266d25.zip
Make dead code check a query.
-rw-r--r--compiler/rustc_interface/src/passes.rs3
-rw-r--r--compiler/rustc_middle/src/query/mod.rs16
-rw-r--r--compiler/rustc_passes/src/dead.rs55
-rw-r--r--compiler/rustc_passes/src/lib.rs1
-rw-r--r--src/test/ui/lint/dead-code/lint-dead-code-1.stderr20
5 files changed, 62 insertions, 33 deletions
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index be31eb89f1b..7a3d77466c5 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -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", || {
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 715a1fa25a1..73128de9848 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -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) }
     }
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 7f15aacc532..e7e56711b33 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -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};
@@ -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> {
@@ -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;
@@ -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()
@@ -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,
@@ -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> {
@@ -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());
@@ -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);
                         }
                     }
@@ -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>,
@@ -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 };
 }
diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs
index 2075fee7171..554701ee90f 100644
--- a/compiler/rustc_passes/src/lib.rs
+++ b/compiler/rustc_passes/src/lib.rs
@@ -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);
diff --git a/src/test/ui/lint/dead-code/lint-dead-code-1.stderr b/src/test/ui/lint/dead-code/lint-dead-code-1.stderr
index af97ea98b2b..72e28e7940e 100644
--- a/src/test/ui/lint/dead-code/lint-dead-code-1.stderr
+++ b/src/test/ui/lint/dead-code/lint-dead-code-1.stderr
@@ -1,8 +1,8 @@
-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
@@ -10,12 +10,6 @@ note: the lint level is defined here
 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
    |
@@ -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