Check assoc consts and tys later like assoc fns
This commit is contained in:
parent
5adb489a80
commit
889582e704
12 changed files with 169 additions and 44 deletions
|
|
@ -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 { .. }
|
||||
|
|
|
|||
44
tests/ui/associated-consts/equality-unused-issue-126729.rs
Normal file
44
tests/ui/associated-consts/equality-unused-issue-126729.rs
Normal 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();
|
||||
}
|
||||
|
|
@ -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> {}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
//@ run-rustfix
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::ops::Add;
|
||||
|
||||
struct A<B>(B);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
//@ run-rustfix
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::ops::Add;
|
||||
|
||||
struct A<B>(B);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
| ^
|
||||
|
|
|
|||
13
tests/ui/lint/dead-code/unused-trait-with-assoc-const.rs
Normal file
13
tests/ui/lint/dead-code/unused-trait-with-assoc-const.rs
Normal 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() {}
|
||||
20
tests/ui/lint/dead-code/unused-trait-with-assoc-const.stderr
Normal file
20
tests/ui/lint/dead-code/unused-trait-with-assoc-const.stderr
Normal 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
|
||||
|
||||
11
tests/ui/lint/dead-code/unused-trait-with-assoc-ty.rs
Normal file
11
tests/ui/lint/dead-code/unused-trait-with-assoc-ty.rs
Normal 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() {}
|
||||
20
tests/ui/lint/dead-code/unused-trait-with-assoc-ty.stderr
Normal file
20
tests/ui/lint/dead-code/unused-trait-with-assoc-ty.stderr
Normal 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
|
||||
|
||||
|
|
@ -15,7 +15,7 @@ impl<T: std::fmt::Display> Foo<T> {
|
|||
}
|
||||
}
|
||||
|
||||
trait Tr { //~ WARN trait `Tr` is never used
|
||||
trait Tr {
|
||||
type U;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue