Skip to content

Commit 8449d10

Browse files
committed
Extend rules of dead code analysis for impls for adts to impls for types refer to adts
1 parent bae813a commit 8449d10

File tree

3 files changed

+87
-10
lines changed

3 files changed

+87
-10
lines changed

compiler/rustc_passes/src/dead.rs

+22-10
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,24 @@ impl Publicness {
5454
}
5555
}
5656

57-
fn struct_all_fields_are_public(tcx: TyCtxt<'_>, id: DefId) -> bool {
57+
fn adt_of<'tcx>(ty: &hir::Ty<'tcx>) -> Option<(LocalDefId, DefKind)> {
58+
match ty.kind {
59+
TyKind::Path(hir::QPath::Resolved(_, path)) => {
60+
if let Res::Def(def_kind, def_id) = path.res
61+
&& let Some(local_def_id) = def_id.as_local()
62+
{
63+
Some((local_def_id, def_kind))
64+
} else {
65+
None
66+
}
67+
}
68+
TyKind::Slice(ty) | TyKind::Array(ty, _) => adt_of(ty),
69+
TyKind::Ptr(ty) | TyKind::Ref(_, ty) => adt_of(ty.ty),
70+
_ => None,
71+
}
72+
}
73+
74+
fn struct_all_fields_are_public(tcx: TyCtxt<'_>, id: LocalDefId) -> bool {
5875
// treat PhantomData and positional ZST as public,
5976
// we don't want to lint types which only have them,
6077
// cause it's a common way to use such types to check things like well-formedness
@@ -79,10 +96,7 @@ fn struct_all_fields_are_public(tcx: TyCtxt<'_>, id: DefId) -> bool {
7996
/// for enum and union, just check they are public,
8097
/// and doesn't solve types like &T for now, just skip them
8198
fn ty_ref_to_pub_struct(tcx: TyCtxt<'_>, ty: &hir::Ty<'_>) -> Publicness {
82-
if let TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind
83-
&& let Res::Def(def_kind, def_id) = path.res
84-
&& def_id.is_local()
85-
{
99+
if let Some((def_id, def_kind)) = adt_of(ty) {
86100
return match def_kind {
87101
DefKind::Enum | DefKind::Union => {
88102
let ty_is_public = tcx.visibility(def_id).is_public();
@@ -584,10 +598,8 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
584598
}
585599

586600
fn impl_item_with_used_self(&mut self, impl_id: hir::ItemId, impl_item_id: LocalDefId) -> bool {
587-
if let TyKind::Path(hir::QPath::Resolved(_, path)) =
588-
self.tcx.hir().item(impl_id).expect_impl().self_ty.kind
589-
&& let Res::Def(def_kind, def_id) = path.res
590-
&& let Some(local_def_id) = def_id.as_local()
601+
if let Some((local_def_id, def_kind)) =
602+
adt_of(self.tcx.hir().item(impl_id).expect_impl().self_ty)
591603
&& matches!(def_kind, DefKind::Struct | DefKind::Enum | DefKind::Union)
592604
{
593605
if let Some(trait_item_id) = self.tcx.associated_item(impl_item_id).trait_item_def_id
@@ -931,7 +943,7 @@ fn create_and_seed_worklist(
931943
match tcx.def_kind(id) {
932944
DefKind::Impl { .. } => false,
933945
DefKind::AssocConst | DefKind::AssocTy | DefKind::AssocFn => !matches!(tcx.associated_item(id).container, AssocItemContainer::ImplContainer),
934-
DefKind::Struct => struct_all_fields_are_public(tcx, id.to_def_id()) || has_allow_dead_code_or_lang_attr(tcx, id).is_some(),
946+
DefKind::Struct => struct_all_fields_are_public(tcx, id) || has_allow_dead_code_or_lang_attr(tcx, id).is_some(),
935947
_ => true
936948
})
937949
.map(|id| (id, ComesFromAllowExpect::No))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#![deny(dead_code)]
2+
3+
struct Foo; //~ ERROR struct `Foo` is never constructed
4+
5+
trait Trait { //~ ERROR trait `Trait` is never used
6+
fn foo(&self) {}
7+
}
8+
9+
impl Trait for Foo {}
10+
11+
impl Trait for [Foo] {}
12+
impl<const N: usize> Trait for [Foo; N] {}
13+
14+
impl Trait for *const Foo {}
15+
impl Trait for *mut Foo {}
16+
17+
impl Trait for &Foo {}
18+
impl Trait for &&Foo {}
19+
impl Trait for &mut Foo {}
20+
21+
impl Trait for [&Foo] {}
22+
impl Trait for &[Foo] {}
23+
impl Trait for &*const Foo {}
24+
25+
pub trait Trait2 {
26+
fn foo(&self) {}
27+
}
28+
29+
impl Trait2 for Foo {}
30+
31+
impl Trait2 for [Foo] {}
32+
impl<const N: usize> Trait2 for [Foo; N] {}
33+
34+
impl Trait2 for *const Foo {}
35+
impl Trait2 for *mut Foo {}
36+
37+
impl Trait2 for &Foo {}
38+
impl Trait2 for &&Foo {}
39+
impl Trait2 for &mut Foo {}
40+
41+
impl Trait2 for [&Foo] {}
42+
impl Trait2 for &[Foo] {}
43+
impl Trait2 for &*const Foo {}
44+
45+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: struct `Foo` is never constructed
2+
--> $DIR/unused-impl-for-non-adts.rs:3:8
3+
|
4+
LL | struct Foo;
5+
| ^^^
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/unused-impl-for-non-adts.rs:1:9
9+
|
10+
LL | #![deny(dead_code)]
11+
| ^^^^^^^^^
12+
13+
error: trait `Trait` is never used
14+
--> $DIR/unused-impl-for-non-adts.rs:5:7
15+
|
16+
LL | trait Trait {
17+
| ^^^^^
18+
19+
error: aborting due to 2 previous errors
20+

0 commit comments

Comments
 (0)