From a264bff9d557e9fc468c9fefeabc0c09d4eeea6f Mon Sep 17 00:00:00 2001 From: mu001999 Date: Tue, 18 Jun 2024 15:56:34 +0800 Subject: [PATCH] Mark assoc tys live only if the trait is live --- compiler/rustc_passes/src/dead.rs | 41 +++++++++++-------- .../ui/const-generics/cross_crate_complex.rs | 1 + .../missing-bounds.fixed | 4 ++ .../missing-bounds.rs | 4 ++ .../missing-bounds.stderr | 18 ++++---- .../dead-code/unused-trait-with-assoc-ty.rs | 11 +++++ .../unused-trait-with-assoc-ty.stderr | 20 +++++++++ tests/ui/pattern/issue-22546.rs | 2 +- tests/ui/pattern/issue-22546.stderr | 10 ----- 9 files changed, 75 insertions(+), 36 deletions(-) create mode 100644 tests/ui/lint/dead-code/unused-trait-with-assoc-ty.rs create mode 100644 tests/ui/lint/dead-code/unused-trait-with-assoc-ty.stderr delete mode 100644 tests/ui/pattern/issue-22546.stderr diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 6a74ddc5508a7..7c8c1d251ae03 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -156,7 +156,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { fn handle_res(&mut self, res: Res) { match res { - Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::TyAlias, def_id) => { + Res::Def( + DefKind::Const | DefKind::AssocConst | DefKind::AssocTy | DefKind::TyAlias, + def_id, + ) => { self.check_def_id(def_id); } _ if self.in_pat => {} @@ -442,7 +445,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { intravisit::walk_item(self, item) } hir::ItemKind::ForeignMod { .. } => {} - hir::ItemKind::Trait(..) => { + hir::ItemKind::Trait(_, _, _, _, trait_item_refs) => { for impl_def_id in self.tcx.all_impls(item.owner_id.to_def_id()) { if let Some(local_def_id) = impl_def_id.as_local() && let ItemKind::Impl(impl_ref) = @@ -455,7 +458,12 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { intravisit::walk_path(self, impl_ref.of_trait.unwrap().path); } } - + // mark assoc ty live if the trait is live + for trait_item in trait_item_refs { + if let hir::AssocItemKind::Type = trait_item.kind { + self.check_def_id(trait_item.id.owner_id.to_def_id()); + } + } intravisit::walk_item(self, item) } _ => intravisit::walk_item(self, item), @@ -472,9 +480,8 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { && let ItemKind::Impl(impl_ref) = self.tcx.hir().expect_item(local_impl_id).kind { - if !matches!(trait_item.kind, hir::TraitItemKind::Type(..)) - && !ty_ref_to_pub_struct(self.tcx, impl_ref.self_ty) - .ty_and_all_fields_are_public + if !ty_ref_to_pub_struct(self.tcx, impl_ref.self_ty) + .ty_and_all_fields_are_public { // skip impl-items of non pure pub ty, // cause we don't know the ty is constructed or not, @@ -813,9 +820,8 @@ fn check_item<'tcx>( // for trait impl blocks, // mark the method live if the self_ty is public, // or the method is public and may construct self - if of_trait && matches!(tcx.def_kind(local_def_id), DefKind::AssocTy) - || tcx.visibility(local_def_id).is_public() - && (ty_and_all_fields_are_public || may_construct_self) + if tcx.visibility(local_def_id).is_public() + && (ty_and_all_fields_are_public || may_construct_self) { // if the impl item is public, // and the ty may be constructed or can be constructed in foreign crates, @@ -852,10 +858,13 @@ fn check_trait_item( worklist: &mut Vec<(LocalDefId, ComesFromAllowExpect)>, id: hir::TraitItemId, ) { - use hir::TraitItemKind::{Const, Fn}; - if matches!(tcx.def_kind(id.owner_id), DefKind::AssocConst | DefKind::AssocFn) { + use hir::TraitItemKind::{Const, Fn, Type}; + if matches!( + tcx.def_kind(id.owner_id), + DefKind::AssocConst | DefKind::AssocTy | DefKind::AssocFn + ) { let trait_item = tcx.hir().trait_item(id); - if matches!(trait_item.kind, Const(_, Some(_)) | Fn(..)) + if matches!(trait_item.kind, Const(_, Some(_)) | Type(_, Some(_)) | Fn(..)) && let Some(comes_from_allow) = has_allow_dead_code_or_lang_attr(tcx, trait_item.owner_id.def_id) { @@ -897,7 +906,7 @@ fn create_and_seed_worklist( // checks impls, impl-items and pub structs with all public fields later match tcx.def_kind(id) { DefKind::Impl { .. } => false, - DefKind::AssocConst | DefKind::AssocFn => !matches!(tcx.associated_item(id).container, AssocItemContainer::ImplContainer), + DefKind::AssocConst | DefKind::AssocTy | DefKind::AssocFn => !matches!(tcx.associated_item(id).container, AssocItemContainer::ImplContainer), DefKind::Struct => struct_all_fields_are_public(tcx, id.to_def_id()) || has_allow_dead_code_or_lang_attr(tcx, id).is_some(), _ => true }) @@ -1132,6 +1141,7 @@ impl<'tcx> DeadVisitor<'tcx> { } match self.tcx.def_kind(def_id) { DefKind::AssocConst + | DefKind::AssocTy | DefKind::AssocFn | DefKind::Fn | DefKind::Static { .. } @@ -1173,15 +1183,14 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) { || (def_kind == DefKind::Trait && live_symbols.contains(&item.owner_id.def_id)) { for &def_id in tcx.associated_item_def_ids(item.owner_id.def_id) { - // We have diagnosed unused assoc consts and fns in traits + // We have diagnosed unused assocs in traits if matches!(def_kind, DefKind::Impl { of_trait: true }) - && matches!(tcx.def_kind(def_id), DefKind::AssocConst | DefKind::AssocFn) + && matches!(tcx.def_kind(def_id), DefKind::AssocConst | DefKind::AssocTy | DefKind::AssocFn) // skip unused public inherent methods, // cause we have diagnosed unconstructed struct || matches!(def_kind, DefKind::Impl { of_trait: false }) && tcx.visibility(def_id).is_public() && ty_ref_to_pub_struct(tcx, tcx.hir().item(item).expect_impl().self_ty).ty_is_public - || def_kind == DefKind::Trait && tcx.def_kind(def_id) == DefKind::AssocTy { continue; } diff --git a/tests/ui/const-generics/cross_crate_complex.rs b/tests/ui/const-generics/cross_crate_complex.rs index d13b69aa0cfb4..b44d889f5e99e 100644 --- a/tests/ui/const-generics/cross_crate_complex.rs +++ b/tests/ui/const-generics/cross_crate_complex.rs @@ -11,6 +11,7 @@ async fn foo() { async_in_foo(async_out_foo::<4>().await).await; } +#[allow(dead_code)] struct Faz; impl Foo for Faz {} diff --git a/tests/ui/generic-associated-types/missing-bounds.fixed b/tests/ui/generic-associated-types/missing-bounds.fixed index 703d3c1e0fb17..ff69016d8626d 100644 --- a/tests/ui/generic-associated-types/missing-bounds.fixed +++ b/tests/ui/generic-associated-types/missing-bounds.fixed @@ -2,6 +2,7 @@ use std::ops::Add; +#[allow(dead_code)] struct A(B); impl Add for A where B: Add { @@ -12,6 +13,7 @@ impl Add for A where B: Add { } } +#[allow(dead_code)] struct C(B); impl> Add for C { @@ -22,6 +24,7 @@ impl> Add for C { } } +#[allow(dead_code)] struct D(B); impl> Add for D { @@ -32,6 +35,7 @@ impl> Add for D { } } +#[allow(dead_code)] struct E(B); impl> Add for E where B: Add { diff --git a/tests/ui/generic-associated-types/missing-bounds.rs b/tests/ui/generic-associated-types/missing-bounds.rs index f40b422887311..1f83356c2fa6b 100644 --- a/tests/ui/generic-associated-types/missing-bounds.rs +++ b/tests/ui/generic-associated-types/missing-bounds.rs @@ -2,6 +2,7 @@ use std::ops::Add; +#[allow(dead_code)] struct A(B); impl Add for A where B: Add { @@ -12,6 +13,7 @@ impl Add for A where B: Add { } } +#[allow(dead_code)] struct C(B); impl Add for C { @@ -22,6 +24,7 @@ impl Add for C { } } +#[allow(dead_code)] struct D(B); impl Add for D { @@ -32,6 +35,7 @@ impl Add for D { } } +#[allow(dead_code)] struct E(B); impl Add for E where ::Output = B { diff --git a/tests/ui/generic-associated-types/missing-bounds.stderr b/tests/ui/generic-associated-types/missing-bounds.stderr index 1d7d80d1b0768..0f0dc24c06c0f 100644 --- a/tests/ui/generic-associated-types/missing-bounds.stderr +++ b/tests/ui/generic-associated-types/missing-bounds.stderr @@ -1,5 +1,5 @@ error: equality constraints are not yet supported in `where` clauses - --> $DIR/missing-bounds.rs:37:33 + --> $DIR/missing-bounds.rs:41:33 | LL | impl Add for E where ::Output = B { | ^^^^^^^^^^^^^^^^^^^^^^ not supported @@ -11,7 +11,7 @@ LL | impl Add for E where B: Add { | ~~~~~~~~~~~~~~~~~~ error[E0308]: mismatched types - --> $DIR/missing-bounds.rs:11:11 + --> $DIR/missing-bounds.rs:12:11 | LL | impl Add for A where B: Add { | - expected this type parameter @@ -24,14 +24,14 @@ LL | A(self.0 + rhs.0) = note: expected type parameter `B` found associated type `::Output` help: the type constructed contains `::Output` due to the type of the argument passed - --> $DIR/missing-bounds.rs:11:9 + --> $DIR/missing-bounds.rs:12:9 | LL | A(self.0 + rhs.0) | ^^--------------^ | | | this argument influences the type of `A` note: tuple struct defined here - --> $DIR/missing-bounds.rs:5:8 + --> $DIR/missing-bounds.rs:6:8 | LL | struct A(B); | ^ @@ -41,7 +41,7 @@ LL | impl Add for A where B: Add { | ++++++++++++ error[E0308]: mismatched types - --> $DIR/missing-bounds.rs:21:14 + --> $DIR/missing-bounds.rs:23:14 | LL | impl Add for C { | - expected this type parameter @@ -54,7 +54,7 @@ LL | Self(self.0 + rhs.0) = note: expected type parameter `B` found associated type `::Output` note: tuple struct defined here - --> $DIR/missing-bounds.rs:15:8 + --> $DIR/missing-bounds.rs:17:8 | LL | struct C(B); | ^ @@ -64,7 +64,7 @@ LL | impl> Add for C { | ++++++++++++ error[E0369]: cannot add `B` to `B` - --> $DIR/missing-bounds.rs:31:21 + --> $DIR/missing-bounds.rs:34:21 | LL | Self(self.0 + rhs.0) | ------ ^ ----- B @@ -77,7 +77,7 @@ LL | impl> Add for D { | +++++++++++++++++++++++++++ error[E0308]: mismatched types - --> $DIR/missing-bounds.rs:42:14 + --> $DIR/missing-bounds.rs:46:14 | LL | impl Add for E where ::Output = B { | - expected this type parameter @@ -90,7 +90,7 @@ LL | Self(self.0 + rhs.0) = note: expected type parameter `B` found associated type `::Output` note: tuple struct defined here - --> $DIR/missing-bounds.rs:35:8 + --> $DIR/missing-bounds.rs:39:8 | LL | struct E(B); | ^ diff --git a/tests/ui/lint/dead-code/unused-trait-with-assoc-ty.rs b/tests/ui/lint/dead-code/unused-trait-with-assoc-ty.rs new file mode 100644 index 0000000000000..e8116d83ebf1c --- /dev/null +++ b/tests/ui/lint/dead-code/unused-trait-with-assoc-ty.rs @@ -0,0 +1,11 @@ +#![deny(dead_code)] + +struct T1; //~ ERROR struct `T1` is never constructed + +trait Foo { type Unused; } //~ ERROR trait `Foo` is never used +impl Foo for T1 { type Unused = Self; } + +pub trait Bar { type Used; } +impl Bar for T1 { type Used = Self; } + +fn main() {} diff --git a/tests/ui/lint/dead-code/unused-trait-with-assoc-ty.stderr b/tests/ui/lint/dead-code/unused-trait-with-assoc-ty.stderr new file mode 100644 index 0000000000000..ab73c64063431 --- /dev/null +++ b/tests/ui/lint/dead-code/unused-trait-with-assoc-ty.stderr @@ -0,0 +1,20 @@ +error: struct `T1` is never constructed + --> $DIR/unused-trait-with-assoc-ty.rs:3:8 + | +LL | struct T1; + | ^^ + | +note: the lint level is defined here + --> $DIR/unused-trait-with-assoc-ty.rs:1:9 + | +LL | #![deny(dead_code)] + | ^^^^^^^^^ + +error: trait `Foo` is never used + --> $DIR/unused-trait-with-assoc-ty.rs:5:7 + | +LL | trait Foo { type Unused; } + | ^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/pattern/issue-22546.rs b/tests/ui/pattern/issue-22546.rs index fd1d5fb6c4775..d5c5b68be78d7 100644 --- a/tests/ui/pattern/issue-22546.rs +++ b/tests/ui/pattern/issue-22546.rs @@ -15,7 +15,7 @@ impl Foo { } } -trait Tr { //~ WARN trait `Tr` is never used +trait Tr { type U; } diff --git a/tests/ui/pattern/issue-22546.stderr b/tests/ui/pattern/issue-22546.stderr deleted file mode 100644 index e067a95e4226c..0000000000000 --- a/tests/ui/pattern/issue-22546.stderr +++ /dev/null @@ -1,10 +0,0 @@ -warning: trait `Tr` is never used - --> $DIR/issue-22546.rs:18:7 - | -LL | trait Tr { - | ^^ - | - = note: `#[warn(dead_code)]` on by default - -warning: 1 warning emitted -