@@ -15,7 +15,7 @@ use rustc_hir::{Node, PatKind, TyKind};
1515use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
1616use rustc_middle::middle::privacy::Level;
1717use rustc_middle::query::Providers;
18- use rustc_middle::ty::{self, AssocItemContainer, TyCtxt};
18+ use rustc_middle::ty::{self, AssocItemContainer, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor };
1919use rustc_middle::{bug, span_bug};
2020use rustc_session::lint;
2121use 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
592638impl<'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
@@ -722,6 +784,41 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
722784
723785 self.in_pat = in_pat;
724786 }
787+
788+ fn visit_poly_trait_ref(&mut self, t: &'tcx hir::PolyTraitRef<'tcx>) {
789+ // mark the assoc type/const appears in poly-trait-ref live
790+ if let Some(pathsegment) = t.trait_ref.path.segments.last()
791+ && let Some(args) = pathsegment.args
792+ {
793+ for constraint in args.constraints {
794+ if let Some(item) = self
795+ .tcx
796+ .associated_items(pathsegment.res.def_id())
797+ .filter_by_name_unhygienic(constraint.ident.name)
798+ .find(|i| {
799+ matches!(i.kind, ty::AssocKind::Const | ty::AssocKind::Type)
800+ && i.ident(self.tcx).normalize_to_macros_2_0() == constraint.ident
801+ })
802+ && let Some(local_def_id) = item.def_id.as_local()
803+ {
804+ self.worklist.push((local_def_id, ComesFromAllowExpect::No));
805+ }
806+ }
807+ }
808+ intravisit::walk_poly_trait_ref(self, t);
809+ }
810+ }
811+
812+ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for MarkSymbolVisitor<'tcx> {
813+ fn visit_ty(&mut self, ty: Ty<'tcx>) {
814+ match ty.kind() {
815+ ty::Alias(_, alias) => {
816+ self.check_def_id(alias.def_id);
817+ }
818+ _ => (),
819+ }
820+ ty.super_visit_with(self);
821+ }
725822}
726823
727824fn has_allow_dead_code_or_lang_attr(
0 commit comments