summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_passes/src/dead.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
commitef24de24a82fe681581cc130f342363c47c0969a (patch)
tree0d494f7e1a38b95c92426f58fe6eaa877303a86c /compiler/rustc_passes/src/dead.rs
parentReleasing progress-linux version 1.74.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-ef24de24a82fe681581cc130f342363c47c0969a.tar.xz
rustc-ef24de24a82fe681581cc130f342363c47c0969a.zip
Merging upstream version 1.75.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_passes/src/dead.rs')
-rw-r--r--compiler/rustc_passes/src/dead.rs98
1 files changed, 52 insertions, 46 deletions
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 493daf314..2e8c58b02 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -1,6 +1,7 @@
-// This implements the dead-code warning pass. It follows middle::reachable
-// closely. The idea is that all reachable symbols are live, codes called
-// from live codes are live, and everything else is dead.
+// This implements the dead-code warning pass.
+// All reachable symbols are live, code called from live code is live, code with certain lint
+// expectations such as `#[expect(unused)]` and `#[expect(dead_code)]` is live, and everything else
+// is dead.
use hir::def_id::{LocalDefIdMap, LocalDefIdSet};
use itertools::Itertools;
@@ -192,15 +193,15 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
if let hir::ExprKind::Assign(lhs, rhs, _) = assign.kind
&& check_for_self_assign_helper(self.typeck_results(), lhs, rhs)
- && !assign.span.from_expansion()
+ && !assign.span.from_expansion()
{
- let is_field_assign = matches!(lhs.kind, hir::ExprKind::Field(..));
- self.tcx.emit_spanned_lint(
- lint::builtin::DEAD_CODE,
- assign.hir_id,
- assign.span,
- UselessAssignment { is_field_assign, ty: self.typeck_results().expr_ty(lhs) }
- )
+ let is_field_assign = matches!(lhs.kind, hir::ExprKind::Field(..));
+ self.tcx.emit_spanned_lint(
+ lint::builtin::DEAD_CODE,
+ assign.hir_id,
+ assign.span,
+ UselessAssignment { is_field_assign, ty: self.typeck_results().expr_ty(lhs) },
+ )
}
}
@@ -256,10 +257,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
let mut current_ty = container;
- for &index in indices {
+ for &(variant, field) in indices {
match current_ty.kind() {
ty::Adt(def, subst) => {
- let field = &def.non_enum_variant().fields[index];
+ let field = &def.variant(variant).fields[field];
self.insert_def_id(field.did);
let field_ty = field.ty(self.tcx, subst);
@@ -270,7 +271,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
// but we may need to mark subfields
ty::Tuple(tys) => {
current_ty =
- self.tcx.normalize_erasing_regions(param_env, tys[index.as_usize()]);
+ self.tcx.normalize_erasing_regions(param_env, tys[field.as_usize()]);
}
_ => span_bug!(expr.span, "named field access on non-ADT"),
}
@@ -670,7 +671,8 @@ fn check_trait_item(
if matches!(tcx.def_kind(id.owner_id), DefKind::AssocConst | DefKind::AssocFn) {
let trait_item = tcx.hir().trait_item(id);
if matches!(trait_item.kind, Const(_, Some(_)) | Fn(_, hir::TraitFn::Provided(_)))
- && let Some(comes_from_allow) = has_allow_dead_code_or_lang_attr(tcx, trait_item.owner_id.def_id)
+ && let Some(comes_from_allow) =
+ has_allow_dead_code_or_lang_attr(tcx, trait_item.owner_id.def_id)
{
worklist.push((trait_item.owner_id.def_id, comes_from_allow));
}
@@ -747,7 +749,7 @@ fn live_symbols_and_ignored_derived_traits(
(symbol_visitor.live_symbols, symbol_visitor.ignored_derived_traits)
}
-struct DeadVariant {
+struct DeadItem {
def_id: LocalDefId,
name: Symbol,
level: lint::Level,
@@ -785,7 +787,13 @@ impl<'tcx> DeadVisitor<'tcx> {
ShouldWarnAboutField::Yes(is_positional)
}
- fn warn_multiple_dead_codes(
+ // # Panics
+ // All `dead_codes` must have the same lint level, otherwise we will intentionally ICE.
+ // This is because we emit a multi-spanned lint using the lint level of the `dead_codes`'s
+ // first local def id.
+ // Prefer calling `Self.warn_dead_code` or `Self.warn_dead_code_grouped_by_lint_level`
+ // since those methods group by lint level before calling this method.
+ fn lint_at_single_level(
&self,
dead_codes: &[LocalDefId],
participle: &str,
@@ -796,6 +804,15 @@ impl<'tcx> DeadVisitor<'tcx> {
return;
};
let tcx = self.tcx;
+
+ let first_hir_id = tcx.hir().local_def_id_to_hir_id(first_id);
+ let first_lint_level = tcx.lint_level_at_node(lint::builtin::DEAD_CODE, first_hir_id).0;
+ assert!(dead_codes.iter().skip(1).all(|id| {
+ let hir_id = tcx.hir().local_def_id_to_hir_id(*id);
+ let level = tcx.lint_level_at_node(lint::builtin::DEAD_CODE, hir_id).0;
+ level == first_lint_level
+ }));
+
let names: Vec<_> =
dead_codes.iter().map(|&def_id| tcx.item_name(def_id.to_def_id())).collect();
let spans: Vec<_> = dead_codes
@@ -876,31 +893,26 @@ impl<'tcx> DeadVisitor<'tcx> {
}
};
- self.tcx.emit_spanned_lint(
- lint,
- tcx.hir().local_def_id_to_hir_id(first_id),
- MultiSpan::from_spans(spans),
- diag,
- );
+ self.tcx.emit_spanned_lint(lint, first_hir_id, MultiSpan::from_spans(spans), diag);
}
- fn warn_dead_fields_and_variants(
+ fn warn_multiple(
&self,
def_id: LocalDefId,
participle: &str,
- dead_codes: Vec<DeadVariant>,
+ dead_codes: Vec<DeadItem>,
is_positional: bool,
) {
let mut dead_codes = dead_codes
.iter()
.filter(|v| !v.name.as_str().starts_with('_'))
- .collect::<Vec<&DeadVariant>>();
+ .collect::<Vec<&DeadItem>>();
if dead_codes.is_empty() {
return;
}
dead_codes.sort_by_key(|v| v.level);
for (_, group) in &dead_codes.into_iter().group_by(|v| v.level) {
- self.warn_multiple_dead_codes(
+ self.lint_at_single_level(
&group.map(|v| v.def_id).collect::<Vec<_>>(),
participle,
Some(def_id),
@@ -910,7 +922,7 @@ impl<'tcx> DeadVisitor<'tcx> {
}
fn warn_dead_code(&mut self, id: LocalDefId, participle: &str) {
- self.warn_multiple_dead_codes(&[id], participle, None, false);
+ self.lint_at_single_level(&[id], participle, None, false);
}
fn check_definition(&mut self, def_id: LocalDefId) {
@@ -954,17 +966,16 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
if let hir::ItemKind::Impl(impl_item) = tcx.hir().item(item).kind {
let mut dead_items = Vec::new();
for item in impl_item.items {
- let did = item.id.owner_id.def_id;
- if !visitor.is_live_code(did) {
- dead_items.push(did)
+ let def_id = item.id.owner_id.def_id;
+ if !visitor.is_live_code(def_id) {
+ let name = tcx.item_name(def_id.to_def_id());
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+ let level = tcx.lint_level_at_node(lint::builtin::DEAD_CODE, hir_id).0;
+
+ dead_items.push(DeadItem { def_id, name, level })
}
}
- visitor.warn_multiple_dead_codes(
- &dead_items,
- "used",
- Some(item.owner_id.def_id),
- false,
- );
+ visitor.warn_multiple(item.owner_id.def_id, "used", dead_items, false);
}
if !live_symbols.contains(&item.owner_id.def_id) {
@@ -988,7 +999,7 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
// Record to group diagnostics.
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let level = tcx.lint_level_at_node(lint::builtin::DEAD_CODE, hir_id).0;
- dead_variants.push(DeadVariant { def_id, name: variant.name, level });
+ dead_variants.push(DeadItem { def_id, name: variant.name, level });
continue;
}
@@ -1013,21 +1024,16 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
hir_id,
)
.0;
- Some(DeadVariant { def_id, name: field.name, level })
+ Some(DeadItem { def_id, name: field.name, level })
} else {
None
}
})
.collect();
- visitor.warn_dead_fields_and_variants(def_id, "read", dead_fields, is_positional)
+ visitor.warn_multiple(def_id, "read", dead_fields, is_positional);
}
- visitor.warn_dead_fields_and_variants(
- item.owner_id.def_id,
- "constructed",
- dead_variants,
- false,
- );
+ visitor.warn_multiple(item.owner_id.def_id, "constructed", dead_variants, false);
}
}