Skip to content

Commit 7de9fe4

Browse files
committed
Lint unused assoc tys although the trait is used
1 parent 2e63026 commit 7de9fe4

File tree

16 files changed

+184
-22
lines changed

16 files changed

+184
-22
lines changed

compiler/rustc_passes/src/dead.rs

+123-8
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use rustc_hir::{Node, PatKind, TyKind};
1717
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
1818
use rustc_middle::middle::privacy::Level;
1919
use rustc_middle::query::Providers;
20-
use rustc_middle::ty::{self, AssocItemContainer, TyCtxt};
20+
use rustc_middle::ty::{self, AssocItemContainer, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor};
2121
use rustc_middle::{bug, span_bug};
2222
use rustc_session::lint;
2323
use rustc_session::lint::builtin::DEAD_CODE;
@@ -465,7 +465,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
465465
intravisit::walk_item(self, item)
466466
}
467467
hir::ItemKind::ForeignMod { .. } => {}
468-
hir::ItemKind::Trait(_, _, _, _, trait_item_refs) => {
468+
hir::ItemKind::Trait(..) => {
469469
for impl_def_id in self.tcx.all_impls(item.owner_id.to_def_id()) {
470470
if let Some(local_def_id) = impl_def_id.as_local()
471471
&& let ItemKind::Impl(impl_ref) =
@@ -478,12 +478,13 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
478478
intravisit::walk_path(self, impl_ref.of_trait.unwrap().path);
479479
}
480480
}
481-
// mark assoc ty live if the trait is live
482-
for trait_item in trait_item_refs {
483-
if let hir::AssocItemKind::Type = trait_item.kind {
484-
self.check_def_id(trait_item.id.owner_id.to_def_id());
485-
}
486-
}
481+
intravisit::walk_item(self, item)
482+
}
483+
hir::ItemKind::Fn(..) => {
484+
// check `T::Ty` in the types of inputs and output
485+
// the result of type_of maybe different from the fn sig,
486+
// so we also check the fn sig
487+
self.visit_middle_fn_sig(item.owner_id.def_id);
487488
intravisit::walk_item(self, item)
488489
}
489490
_ => intravisit::walk_item(self, item),
@@ -519,6 +520,21 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
519520
}
520521
}
521522
}
523+
524+
match trait_item.kind {
525+
hir::TraitItemKind::Fn(..) => {
526+
// check `T::Ty` in the types of inputs and output
527+
// the result of type_of maybe different from the fn sig,
528+
// so we also check the fn sig
529+
self.visit_middle_fn_sig(trait_item.owner_id.def_id)
530+
}
531+
hir::TraitItemKind::Type(.., Some(_)) | hir::TraitItemKind::Const(..) => {
532+
// check `type X = T::Ty;` or `const X: T::Ty;`
533+
self.visit_middle_ty_by_def_id(trait_item.owner_id.def_id)
534+
}
535+
_ => (),
536+
}
537+
522538
intravisit::walk_trait_item(self, trait_item);
523539
}
524540
Node::ImplItem(impl_item) => {
@@ -540,6 +556,20 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
540556
_ => {}
541557
}
542558
}
559+
560+
match impl_item.kind {
561+
hir::ImplItemKind::Fn(..) => {
562+
// check `T::Ty` in the types of inputs and output
563+
// the result of type_of maybe different from the fn sig,
564+
// so we also check the fn sig
565+
self.visit_middle_fn_sig(impl_item.owner_id.def_id)
566+
}
567+
hir::ImplItemKind::Type(..) | hir::ImplItemKind::Const(..) => {
568+
// check `type X = T::Ty;` or `const X: T::Ty;`
569+
self.visit_middle_ty_by_def_id(impl_item.owner_id.def_id)
570+
}
571+
}
572+
543573
intravisit::walk_impl_item(self, impl_item);
544574
}
545575
Node::ForeignItem(foreign_item) => {
@@ -600,6 +630,22 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
600630
false
601631
}
602632
}
633+
634+
fn visit_middle_ty(&mut self, ty: Ty<'tcx>) {
635+
<Self as TypeVisitor<TyCtxt<'tcx>>>::visit_ty(self, ty);
636+
}
637+
638+
fn visit_middle_ty_by_def_id(&mut self, def_id: LocalDefId) {
639+
self.visit_middle_ty(self.tcx.type_of(def_id).instantiate_identity());
640+
}
641+
642+
fn visit_middle_fn_sig(&mut self, def_id: LocalDefId) {
643+
let fn_sig = self.tcx.fn_sig(def_id).instantiate_identity();
644+
for ty in fn_sig.inputs().skip_binder() {
645+
self.visit_middle_ty(ty.clone());
646+
}
647+
self.visit_middle_ty(fn_sig.output().skip_binder().clone());
648+
}
603649
}
604650

605651
impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
@@ -631,6 +677,19 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
631677
intravisit::walk_struct_def(self, def);
632678
}
633679

680+
fn visit_field_def(&mut self, s: &'tcx rustc_hir::FieldDef<'tcx>) {
681+
// check `field: T::Ty`
682+
// marks assoc types live whether the field is not used or not
683+
// there are three situations:
684+
// 1. the field is used, it's good
685+
// 2. the field is not used but marked like `#[allow(dead_code)]`,
686+
// it's annoying to mark the assoc type `#[allow(dead_code)]` again
687+
// 3. the field is not used, and will be linted
688+
// the assoc type will be linted after removing the unused field
689+
self.visit_middle_ty_by_def_id(s.def_id);
690+
intravisit::walk_field_def(self, s);
691+
}
692+
634693
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
635694
match expr.kind {
636695
hir::ExprKind::Path(ref qpath @ hir::QPath::TypeRelative(..)) => {
@@ -663,6 +722,9 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
663722
_ => (),
664723
}
665724

725+
// check the expr_ty if its type is `T::Ty`
726+
self.visit_middle_ty(self.typeck_results().expr_ty(expr));
727+
666728
intravisit::walk_expr(self, expr);
667729
}
668730

@@ -703,6 +765,24 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
703765

704766
fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) {
705767
self.handle_res(path.res);
768+
769+
if let Res::Def(def_kind, def_id) = path.res
770+
&& matches!(
771+
def_kind,
772+
DefKind::Fn
773+
| DefKind::AssocFn
774+
| DefKind::AssocTy
775+
| DefKind::Struct
776+
| DefKind::Union
777+
| DefKind::Enum
778+
)
779+
{
780+
let preds = self.tcx.predicates_of(def_id).instantiate_identity(self.tcx);
781+
for pred in preds.iter() {
782+
<Self as TypeVisitor<TyCtxt<'tcx>>>::visit_predicate(self, pred.0.as_predicate());
783+
}
784+
}
785+
706786
intravisit::walk_path(self, path);
707787
}
708788

@@ -735,6 +815,41 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
735815

736816
self.in_pat = in_pat;
737817
}
818+
819+
fn visit_poly_trait_ref(&mut self, t: &'tcx hir::PolyTraitRef<'tcx>) {
820+
// mark the assoc type/const appears in poly-trait-ref live
821+
if let Some(pathsegment) = t.trait_ref.path.segments.last()
822+
&& let Some(args) = pathsegment.args
823+
{
824+
for constraint in args.constraints {
825+
if let Some(item) = self
826+
.tcx
827+
.associated_items(pathsegment.res.def_id())
828+
.filter_by_name_unhygienic(constraint.ident.name)
829+
.find(|i| {
830+
matches!(i.kind, ty::AssocKind::Const | ty::AssocKind::Type)
831+
&& i.ident(self.tcx).normalize_to_macros_2_0() == constraint.ident
832+
})
833+
&& let Some(local_def_id) = item.def_id.as_local()
834+
{
835+
self.worklist.push((local_def_id, ComesFromAllowExpect::No));
836+
}
837+
}
838+
}
839+
intravisit::walk_poly_trait_ref(self, t);
840+
}
841+
}
842+
843+
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for MarkSymbolVisitor<'tcx> {
844+
fn visit_ty(&mut self, ty: Ty<'tcx>) {
845+
match ty.kind() {
846+
ty::Alias(_, alias) => {
847+
self.check_def_id(alias.def_id);
848+
}
849+
_ => (),
850+
}
851+
ty.super_visit_with(self);
852+
}
738853
}
739854

740855
fn has_allow_dead_code_or_lang_attr(

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,20 +27,17 @@ 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 {
37-
use rustc_middle::ty::{Ty, TyCtxt};
35+
use rustc_middle::ty::TyCtxt;
3836

3937
use super::*;
4038

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

library/alloc/src/vec/in_place_collect.rs

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

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

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
}

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

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

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

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

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

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

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

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

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+

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 {

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)