Check assoc consts and tys later like assoc fns

This commit is contained in:
Mu001999 2025-07-06 14:07:25 +08:00
parent 5adb489a80
commit 889582e704
12 changed files with 169 additions and 44 deletions

View file

@ -18,7 +18,7 @@ use rustc_hir::{self as hir, ImplItem, ImplItemKind, Node, PatKind, QPath, TyKin
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::middle::privacy::Level;
use rustc_middle::query::Providers;
use rustc_middle::ty::{self, TyCtxt};
use rustc_middle::ty::{self, AssocTag, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_session::lint::builtin::DEAD_CODE;
use rustc_session::lint::{self, LintExpectationId};
@ -115,7 +115,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 => {}
@ -482,7 +485,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
) -> bool {
let trait_def_id = match self.tcx.def_kind(local_def_id) {
// assoc impl items of traits are live if the corresponding trait items are live
DefKind::AssocFn => self
DefKind::AssocConst | DefKind::AssocTy | DefKind::AssocFn => self
.tcx
.associated_item(local_def_id)
.trait_item_def_id
@ -647,6 +650,31 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
self.in_pat = in_pat;
}
fn visit_trait_ref(&mut self, t: &'tcx hir::TraitRef<'tcx>) {
if let Some(trait_def_id) = t.path.res.opt_def_id()
&& let Some(segment) = t.path.segments.last()
&& let Some(args) = segment.args
{
for constraint in args.constraints {
if let Some(local_def_id) = self
.tcx
.associated_items(trait_def_id)
.find_by_ident_and_kind(
self.tcx,
constraint.ident,
AssocTag::Const,
trait_def_id,
)
.and_then(|item| item.def_id.as_local())
{
self.worklist.push((local_def_id, ComesFromAllowExpect::No));
}
}
}
intravisit::walk_trait_ref(self, t);
}
}
fn has_allow_dead_code_or_lang_attr(
@ -744,18 +772,12 @@ fn check_item<'tcx>(
{
worklist.push((local_def_id, comes_from_allow));
} else if of_trait {
// FIXME: This condition can be removed
// if we support dead check for assoc consts and tys.
if !matches!(tcx.def_kind(local_def_id), DefKind::AssocFn) {
worklist.push((local_def_id, ComesFromAllowExpect::No));
} else {
// We only care about associated items of traits,
// because they cannot be visited directly,
// so we later mark them as live if their corresponding traits
// or trait items and self types are both live,
// but inherent associated items can be visited and marked directly.
unsolved_items.push((id, local_def_id));
}
// We only care about associated items of traits,
// because they cannot be visited directly,
// so we later mark them as live if their corresponding traits
// or trait items and self types are both live,
// but inherent associated items can be visited and marked directly.
unsolved_items.push((id, local_def_id));
}
}
}
@ -791,15 +813,14 @@ 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) {
let trait_item = tcx.hir_trait_item(id);
if matches!(trait_item.kind, Const(_, Some(_)) | Fn(..))
&& 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));
}
use hir::TraitItemKind::{Const, Fn, Type};
let trait_item = tcx.hir_trait_item(id);
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)
{
worklist.push((trait_item.owner_id.def_id, comes_from_allow));
}
}
@ -1163,6 +1184,7 @@ impl<'tcx> DeadVisitor<'tcx> {
}
match self.tcx.def_kind(def_id) {
DefKind::AssocConst
| DefKind::AssocTy
| DefKind::AssocFn
| DefKind::Fn
| DefKind::Static { .. }

View file

@ -0,0 +1,44 @@
//@ check-pass
#![feature(associated_const_equality)]
#![deny(dead_code)]
trait Tr {
const I: i32;
}
impl Tr for () {
const I: i32 = 1;
}
fn foo() -> impl Tr<I = 1> {}
trait Tr2 {
const J: i32;
const K: i32;
}
impl Tr2 for () {
const J: i32 = 1;
const K: i32 = 1;
}
fn foo2() -> impl Tr2<J = 1, K = 1> {}
mod t {
pub trait Tr3 {
const L: i32;
}
impl Tr3 for () {
const L: i32 = 1;
}
}
fn foo3() -> impl t::Tr3<L = 1> {}
fn main() {
foo();
foo2();
foo3();
}

View file

@ -11,6 +11,7 @@ async fn foo() {
async_in_foo(async_out_foo::<4>().await).await;
}
#[allow(dead_code)]
struct Faz<const N: usize>;
impl<const N: usize> Foo<N> for Faz<N> {}

View file

@ -1,5 +1,7 @@
//@ run-rustfix
#![allow(dead_code)]
use std::ops::Add;
struct A<B>(B);

View file

@ -1,5 +1,7 @@
//@ run-rustfix
#![allow(dead_code)]
use std::ops::Add;
struct A<B>(B);

View file

@ -1,5 +1,5 @@
error: equality constraints are not yet supported in `where` clauses
--> $DIR/missing-bounds.rs:37:33
--> $DIR/missing-bounds.rs:39:33
|
LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B {
| ^^^^^^^^^^^^^^^^^^^^^^ not supported
@ -12,7 +12,7 @@ LL + impl<B: Add> Add for E<B> where B: Add<Output = B> {
|
error[E0308]: mismatched types
--> $DIR/missing-bounds.rs:11:11
--> $DIR/missing-bounds.rs:13:11
|
LL | impl<B> Add for A<B> where B: Add {
| - expected this type parameter
@ -25,14 +25,14 @@ LL | A(self.0 + rhs.0)
= note: expected type parameter `B`
found associated type `<B as Add>::Output`
help: the type constructed contains `<B as Add>::Output` due to the type of the argument passed
--> $DIR/missing-bounds.rs:11:9
--> $DIR/missing-bounds.rs:13: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:7:8
|
LL | struct A<B>(B);
| ^
@ -42,7 +42,7 @@ LL | impl<B> Add for A<B> where B: Add<Output = B> {
| ++++++++++++
error[E0308]: mismatched types
--> $DIR/missing-bounds.rs:21:14
--> $DIR/missing-bounds.rs:23:14
|
LL | impl<B: Add> Add for C<B> {
| - expected this type parameter
@ -55,7 +55,7 @@ LL | Self(self.0 + rhs.0)
= note: expected type parameter `B`
found associated type `<B as Add>::Output`
note: tuple struct defined here
--> $DIR/missing-bounds.rs:15:8
--> $DIR/missing-bounds.rs:17:8
|
LL | struct C<B>(B);
| ^
@ -65,7 +65,7 @@ LL | impl<B: Add<Output = B>> Add for C<B> {
| ++++++++++++
error[E0369]: cannot add `B` to `B`
--> $DIR/missing-bounds.rs:31:21
--> $DIR/missing-bounds.rs:33:21
|
LL | Self(self.0 + rhs.0)
| ------ ^ ----- B
@ -78,7 +78,7 @@ LL | impl<B: std::ops::Add<Output = B>> Add for D<B> {
| +++++++++++++++++++++++++++
error[E0308]: mismatched types
--> $DIR/missing-bounds.rs:42:14
--> $DIR/missing-bounds.rs:44:14
|
LL | impl<B: Add> Add for E<B> where <B as Add>::Output = B {
| - expected this type parameter
@ -91,7 +91,7 @@ LL | Self(self.0 + rhs.0)
= note: expected type parameter `B`
found associated type `<B as Add>::Output`
note: tuple struct defined here
--> $DIR/missing-bounds.rs:35:8
--> $DIR/missing-bounds.rs:37:8
|
LL | struct E<B>(B);
| ^

View file

@ -0,0 +1,13 @@
#![deny(dead_code)]
trait Tr { //~ ERROR trait `Tr` is never used
const I: Self;
}
struct Foo; //~ ERROR struct `Foo` is never constructed
impl Tr for Foo {
const I: Self = Foo;
}
fn main() {}

View file

@ -0,0 +1,20 @@
error: trait `Tr` is never used
--> $DIR/unused-trait-with-assoc-const.rs:3:7
|
LL | trait Tr {
| ^^
|
note: the lint level is defined here
--> $DIR/unused-trait-with-assoc-const.rs:1:9
|
LL | #![deny(dead_code)]
| ^^^^^^^^^
error: struct `Foo` is never constructed
--> $DIR/unused-trait-with-assoc-const.rs:7:8
|
LL | struct Foo;
| ^^^
error: aborting due to 2 previous errors

View file

@ -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() {}

View file

@ -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

View file

@ -15,7 +15,7 @@ impl<T: std::fmt::Display> Foo<T> {
}
}
trait Tr { //~ WARN trait `Tr` is never used
trait Tr {
type U;
}

View file

@ -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