Skip to content

Commit 3349501

Browse files
committed
Lint unused assoc tys although the trait is used
1 parent 03c2100 commit 3349501

File tree

16 files changed

+184
-22
lines changed

16 files changed

+184
-22
lines changed

Diff for: compiler/rustc_passes/src/dead.rs

+123-8
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc_hir::{Node, PatKind, TyKind};
1515
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
1616
use rustc_middle::middle::privacy::Level;
1717
use rustc_middle::query::Providers;
18-
use rustc_middle::ty::{self, AssocItemContainer, TyCtxt};
18+
use rustc_middle::ty::{self, AssocItemContainer, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor};
1919
use rustc_middle::{bug, span_bug};
2020
use rustc_session::lint;
2121
use rustc_session::lint::builtin::DEAD_CODE;
@@ -450,7 +450,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
450450
intravisit::walk_item(self, item)
451451
}
452452
hir::ItemKind::ForeignMod { .. } => {}
453-
hir::ItemKind::Trait(_, _, _, _, trait_item_refs) => {
453+
hir::ItemKind::Trait(..) => {
454454
for impl_def_id in self.tcx.all_impls(item.owner_id.to_def_id()) {
455455
if let Some(local_def_id) = impl_def_id.as_local()
456456
&& let ItemKind::Impl(impl_ref) =
@@ -463,12 +463,13 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
463463
intravisit::walk_path(self, impl_ref.of_trait.unwrap().path);
464464
}
465465
}
466-
// mark assoc ty live if the trait is live
467-
for trait_item in trait_item_refs {
468-
if let hir::AssocItemKind::Type = trait_item.kind {
469-
self.check_def_id(trait_item.id.owner_id.to_def_id());
470-
}
471-
}
466+
intravisit::walk_item(self, item)
467+
}
468+
hir::ItemKind::Fn(..) => {
469+
// check `T::Ty` in the types of inputs and output
470+
// the result of type_of maybe different from the fn sig,
471+
// so we also check the fn sig
472+
self.visit_middle_fn_sig(item.owner_id.def_id);
472473
intravisit::walk_item(self, item)
473474
}
474475
_ => intravisit::walk_item(self, item),
@@ -504,6 +505,21 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
504505
}
505506
}
506507
}
508+
509+
match trait_item.kind {
510+
hir::TraitItemKind::Fn(..) => {
511+
// check `T::Ty` in the types of inputs and output
512+
// the result of type_of maybe different from the fn sig,
513+
// so we also check the fn sig
514+
self.visit_middle_fn_sig(trait_item.owner_id.def_id)
515+
}
516+
hir::TraitItemKind::Type(.., Some(_)) | hir::TraitItemKind::Const(..) => {
517+
// check `type X = T::Ty;` or `const X: T::Ty;`
518+
self.visit_middle_ty_by_def_id(trait_item.owner_id.def_id)
519+
}
520+
_ => (),
521+
}
522+
507523
intravisit::walk_trait_item(self, trait_item);
508524
}
509525
Node::ImplItem(impl_item) => {
@@ -525,6 +541,20 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
525541
_ => {}
526542
}
527543
}
544+
545+
match impl_item.kind {
546+
hir::ImplItemKind::Fn(..) => {
547+
// check `T::Ty` in the types of inputs and output
548+
// the result of type_of maybe different from the fn sig,
549+
// so we also check the fn sig
550+
self.visit_middle_fn_sig(impl_item.owner_id.def_id)
551+
}
552+
hir::ImplItemKind::Type(..) | hir::ImplItemKind::Const(..) => {
553+
// check `type X = T::Ty;` or `const X: T::Ty;`
554+
self.visit_middle_ty_by_def_id(impl_item.owner_id.def_id)
555+
}
556+
}
557+
528558
intravisit::walk_impl_item(self, impl_item);
529559
}
530560
Node::ForeignItem(foreign_item) => {
@@ -587,6 +617,22 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
587617
false
588618
}
589619
}
620+
621+
fn visit_middle_ty(&mut self, ty: Ty<'tcx>) {
622+
<Self as TypeVisitor<TyCtxt<'tcx>>>::visit_ty(self, ty);
623+
}
624+
625+
fn visit_middle_ty_by_def_id(&mut self, def_id: LocalDefId) {
626+
self.visit_middle_ty(self.tcx.type_of(def_id).instantiate_identity());
627+
}
628+
629+
fn visit_middle_fn_sig(&mut self, def_id: LocalDefId) {
630+
let fn_sig = self.tcx.fn_sig(def_id).instantiate_identity();
631+
for ty in fn_sig.inputs().skip_binder() {
632+
self.visit_middle_ty(ty.clone());
633+
}
634+
self.visit_middle_ty(fn_sig.output().skip_binder().clone());
635+
}
590636
}
591637

592638
impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
@@ -618,6 +664,19 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
618664
intravisit::walk_struct_def(self, def);
619665
}
620666

667+
fn visit_field_def(&mut self, s: &'tcx rustc_hir::FieldDef<'tcx>) {
668+
// check `field: T::Ty`
669+
// marks assoc types live whether the field is not used or not
670+
// there are three situations:
671+
// 1. the field is used, it's good
672+
// 2. the field is not used but marked like `#[allow(dead_code)]`,
673+
// it's annoying to mark the assoc type `#[allow(dead_code)]` again
674+
// 3. the field is not used, and will be linted
675+
// the assoc type will be linted after removing the unused field
676+
self.visit_middle_ty_by_def_id(s.def_id);
677+
intravisit::walk_field_def(self, s);
678+
}
679+
621680
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
622681
match expr.kind {
623682
hir::ExprKind::Path(ref qpath @ hir::QPath::TypeRelative(..)) => {
@@ -650,6 +709,9 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
650709
_ => (),
651710
}
652711

712+
// check the expr_ty if its type is `T::Ty`
713+
self.visit_middle_ty(self.typeck_results().expr_ty(expr));
714+
653715
intravisit::walk_expr(self, expr);
654716
}
655717

@@ -690,6 +752,24 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
690752

691753
fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) {
692754
self.handle_res(path.res);
755+
756+
if let Res::Def(def_kind, def_id) = path.res
757+
&& matches!(
758+
def_kind,
759+
DefKind::Fn
760+
| DefKind::AssocFn
761+
| DefKind::AssocTy
762+
| DefKind::Struct
763+
| DefKind::Union
764+
| DefKind::Enum
765+
)
766+
{
767+
let preds = self.tcx.predicates_of(def_id).instantiate_identity(self.tcx);
768+
for pred in preds.iter() {
769+
<Self as TypeVisitor<TyCtxt<'tcx>>>::visit_predicate(self, pred.0.as_predicate());
770+
}
771+
}
772+
693773
intravisit::walk_path(self, path);
694774
}
695775

@@ -722,6 +802,41 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
722802

723803
self.in_pat = in_pat;
724804
}
805+
806+
fn visit_poly_trait_ref(&mut self, t: &'tcx hir::PolyTraitRef<'tcx>) {
807+
// mark the assoc type/const appears in poly-trait-ref live
808+
if let Some(pathsegment) = t.trait_ref.path.segments.last()
809+
&& let Some(args) = pathsegment.args
810+
{
811+
for constraint in args.constraints {
812+
if let Some(item) = self
813+
.tcx
814+
.associated_items(pathsegment.res.def_id())
815+
.filter_by_name_unhygienic(constraint.ident.name)
816+
.find(|i| {
817+
matches!(i.kind, ty::AssocKind::Const | ty::AssocKind::Type)
818+
&& i.ident(self.tcx).normalize_to_macros_2_0() == constraint.ident
819+
})
820+
&& let Some(local_def_id) = item.def_id.as_local()
821+
{
822+
self.worklist.push((local_def_id, ComesFromAllowExpect::No));
823+
}
824+
}
825+
}
826+
intravisit::walk_poly_trait_ref(self, t);
827+
}
828+
}
829+
830+
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for MarkSymbolVisitor<'tcx> {
831+
fn visit_ty(&mut self, ty: Ty<'tcx>) {
832+
match ty.kind() {
833+
ty::Alias(_, alias) => {
834+
self.check_def_id(alias.def_id);
835+
}
836+
_ => (),
837+
}
838+
ty.super_visit_with(self);
839+
}
725840
}
726841

727842
fn has_allow_dead_code_or_lang_attr(

Diff for: compiler/rustc_transmute/src/maybe_transmutable/query_context.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use crate::layout;
44
pub(crate) trait QueryContext {
55
type Def: layout::Def;
66
type Ref: layout::Ref;
7-
type Scope: Copy;
87
}
98

109
#[cfg(test)]
@@ -28,19 +27,16 @@ pub(crate) mod test {
2827
impl QueryContext for UltraMinimal {
2928
type Def = Def;
3029
type Ref = !;
31-
type Scope = ();
3230
}
3331
}
3432

3533
#[cfg(feature = "rustc")]
3634
mod rustc {
3735
use super::*;
38-
use rustc_middle::ty::{Ty, TyCtxt};
36+
use rustc_middle::ty::TyCtxt;
3937

4038
impl<'tcx> super::QueryContext for TyCtxt<'tcx> {
4139
type Def = layout::rustc::Def<'tcx>;
4240
type Ref = layout::rustc::Ref<'tcx>;
43-
44-
type Scope = Ty<'tcx>;
4541
}
4642
}

Diff for: library/alloc/src/vec/in_place_collect.rs

+1
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ const fn needs_realloc<SRC, DEST>(src_cap: usize, dst_cap: usize) -> bool {
214214

215215
/// This provides a shorthand for the source type since local type aliases aren't a thing.
216216
#[rustc_specialization_trait]
217+
#[allow(dead_code)]
217218
trait InPlaceCollect: SourceIter<Source: AsVecIntoIter> + InPlaceIterable {
218219
type Src;
219220
}

Diff for: library/core/src/ops/async_function.rs

+1
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ mod internal_implementation_detail {
147147
// of the closure's self-capture, and these upvar types will be instantiated with
148148
// the `'closure_env` region provided to the associated type.
149149
#[lang = "async_fn_kind_upvars"]
150+
#[allow(dead_code)]
150151
type Upvars<'closure_env, Inputs, Upvars, BorrowedUpvarsAsFnPtr>;
151152
}
152153
}

Diff for: tests/ui/associated-type-bounds/union-bounds.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
trait Tr1: Copy { type As1: Copy; }
66
trait Tr2: Copy { type As2: Copy; }
7-
trait Tr3: Copy { type As3: Copy; }
7+
trait Tr3: Copy { #[allow(dead_code)] type As3: Copy; }
88
trait Tr4<'a>: Copy { type As4: Copy; }
99
trait Tr5: Copy { type As5: Copy; }
1010

Diff for: tests/ui/associated-types/impl-wf-cycle-5.fixed

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ impl Fiz for bool {}
1111

1212
trait Grault {
1313
type A;
14+
#[allow(dead_code)]
1415
type B;
1516
}
1617

Diff for: tests/ui/associated-types/impl-wf-cycle-5.rs

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ impl Fiz for bool {}
1111

1212
trait Grault {
1313
type A;
14+
#[allow(dead_code)]
1415
type B;
1516
}
1617

Diff for: tests/ui/associated-types/impl-wf-cycle-5.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
2-
--> $DIR/impl-wf-cycle-5.rs:22:1
2+
--> $DIR/impl-wf-cycle-5.rs:23:1
33
|
44
LL | / impl<T> Grault for (T,)
55
LL | |
@@ -12,7 +12,7 @@ LL | type A = ();
1212
| ------ associated type `<(T,) as Grault>::A` is specified here
1313
|
1414
note: required for `(T,)` to implement `Grault`
15-
--> $DIR/impl-wf-cycle-5.rs:22:9
15+
--> $DIR/impl-wf-cycle-5.rs:23:9
1616
|
1717
LL | impl<T> Grault for (T,)
1818
| ^^^^^^ ^^^^

Diff for: tests/ui/associated-types/impl-wf-cycle-6.fixed

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ impl Fiz for bool {}
1111

1212
trait Grault {
1313
type A;
14+
#[allow(dead_code)]
1415
type B;
1516
}
1617

Diff for: tests/ui/associated-types/impl-wf-cycle-6.rs

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ impl Fiz for bool {}
1111

1212
trait Grault {
1313
type A;
14+
#[allow(dead_code)]
1415
type B;
1516
}
1617

Diff for: tests/ui/associated-types/impl-wf-cycle-6.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _`
2-
--> $DIR/impl-wf-cycle-6.rs:22:1
2+
--> $DIR/impl-wf-cycle-6.rs:23:1
33
|
44
LL | / impl<T: Grault> Grault for (T,)
55
LL | |
@@ -11,7 +11,7 @@ LL | type A = ();
1111
| ------ associated type `<(T,) as Grault>::A` is specified here
1212
|
1313
note: required for `(T,)` to implement `Grault`
14-
--> $DIR/impl-wf-cycle-6.rs:22:17
14+
--> $DIR/impl-wf-cycle-6.rs:23:17
1515
|
1616
LL | impl<T: Grault> Grault for (T,)
1717
| ^^^^^^ ^^^^

Diff for: tests/ui/generic-associated-types/collections.rs

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ trait Collection<T> {
1010
type Iter<'iter>: Iterator<Item=&'iter T> where T: 'iter, Self: 'iter;
1111
type Family: CollectionFamily;
1212
// Test associated type defaults with parameters
13+
#[allow(dead_code)]
1314
type Sibling<U>: Collection<U> =
1415
<<Self as Collection<T>>::Family as CollectionFamily>::Member<U>;
1516

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#![deny(dead_code)]
2+
3+
trait Tr {
4+
type X; //~ ERROR associated type `X` is never used
5+
type Y;
6+
type Z;
7+
}
8+
9+
impl Tr for () {
10+
type X = Self;
11+
type Y = Self;
12+
type Z = Self;
13+
}
14+
15+
trait Tr2 {
16+
type X;
17+
}
18+
19+
fn foo<T: Tr>() -> impl Tr<Y = ()> where T::Z: Copy {}
20+
fn bar<T: ?Sized>() {}
21+
22+
fn main() {
23+
foo::<()>();
24+
bar::<dyn Tr2<X = ()>>();
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error: associated type `X` is never used
2+
--> $DIR/unused-assoc-ty-in-used-trait.rs:4:10
3+
|
4+
LL | trait Tr {
5+
| -- associated type in this trait
6+
LL | type X;
7+
| ^
8+
|
9+
note: the lint level is defined here
10+
--> $DIR/unused-assoc-ty-in-used-trait.rs:1:9
11+
|
12+
LL | #![deny(dead_code)]
13+
| ^^^^^^^^^
14+
15+
error: aborting due to 1 previous error
16+

Diff for: tests/ui/traits/issue-38033.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@ trait Future {
1616

1717
trait IntoFuture {
1818
type Future: Future<Item=Self::Item, Error=Self::Error>;
19+
//~^ WARN associated items `Future` and `into_future` are never used
1920
type Item;
2021
type Error;
2122

22-
fn into_future(self) -> Self::Future; //~ WARN method `into_future` is never used
23+
fn into_future(self) -> Self::Future;
2324
}
2425

2526
impl<F: Future> IntoFuture for F {

Diff for: tests/ui/traits/issue-38033.stderr

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
warning: method `into_future` is never used
2-
--> $DIR/issue-38033.rs:22:8
1+
warning: associated items `Future` and `into_future` are never used
2+
--> $DIR/issue-38033.rs:18:10
33
|
44
LL | trait IntoFuture {
5-
| ---------- method in this trait
5+
| ---------- associated items in this trait
6+
LL | type Future: Future<Item=Self::Item, Error=Self::Error>;
7+
| ^^^^^^
68
...
79
LL | fn into_future(self) -> Self::Future;
810
| ^^^^^^^^^^^

0 commit comments

Comments
 (0)