11use rustc_hir:: intravisit;
2- use rustc_hir:: { self , Body , FnDecl , HirId , HirIdSet , ItemKind , Node } ;
2+ use rustc_hir:: { self , AssocItemKind , Body , FnDecl , HirId , HirIdSet , ItemKind , Node } ;
33use rustc_infer:: infer:: TyCtxtInferExt ;
44use rustc_lint:: { LateContext , LateLintPass } ;
5- use rustc_middle:: ty:: { self , Ty } ;
5+ use rustc_middle:: ty:: { self , TraitRef , Ty } ;
66use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
77use rustc_span:: source_map:: Span ;
8+ use rustc_span:: symbol:: kw;
89use rustc_target:: abi:: LayoutOf ;
910use rustc_target:: spec:: abi:: Abi ;
1011use rustc_typeck:: expr_use_visitor:: { ConsumeMode , Delegate , ExprUseVisitor , PlaceBase , PlaceWithHirId } ;
1112
12- use crate :: utils:: span_lint;
13+ use crate :: utils:: { contains_ty , span_lint} ;
1314
1415#[ derive( Copy , Clone ) ]
1516pub struct BoxedLocal {
@@ -51,6 +52,7 @@ fn is_non_trait_box(ty: Ty<'_>) -> bool {
5152struct EscapeDelegate < ' a , ' tcx > {
5253 cx : & ' a LateContext < ' tcx > ,
5354 set : HirIdSet ,
55+ trait_self_ty : Option < Ty < ' a > > ,
5456 too_large_for_stack : u64 ,
5557}
5658
@@ -72,19 +74,34 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
7274 }
7375 }
7476
75- // If the method is an impl for a trait, don't warn.
7677 let parent_id = cx. tcx . hir ( ) . get_parent_item ( hir_id) ;
7778 let parent_node = cx. tcx . hir ( ) . find ( parent_id) ;
7879
80+ let mut trait_self_ty = None ;
7981 if let Some ( Node :: Item ( item) ) = parent_node {
82+ // If the method is an impl for a trait, don't warn.
8083 if let ItemKind :: Impl { of_trait : Some ( _) , .. } = item. kind {
8184 return ;
8285 }
86+
87+ // find `self` ty for this trait if relevant
88+ if let ItemKind :: Trait ( _, _, _, _, items) = item. kind {
89+ for trait_item in items {
90+ if trait_item. id . hir_id == hir_id {
91+ // be sure we have `self` parameter in this function
92+ if let AssocItemKind :: Fn { has_self : true } = trait_item. kind {
93+ trait_self_ty =
94+ Some ( TraitRef :: identity ( cx. tcx , trait_item. id . hir_id . owner . to_def_id ( ) ) . self_ty ( ) ) ;
95+ }
96+ }
97+ }
98+ }
8399 }
84100
85101 let mut v = EscapeDelegate {
86102 cx,
87103 set : HirIdSet :: default ( ) ,
104+ trait_self_ty,
88105 too_large_for_stack : self . too_large_for_stack ,
89106 } ;
90107
@@ -153,6 +170,14 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
153170 return ;
154171 }
155172
173+ // skip if there is a `self` parameter binding to a type
174+ // that contains `Self` (i.e.: `self: Box<Self>`), see #4804
175+ if let Some ( trait_self_ty) = self . trait_self_ty {
176+ if map. name ( cmt. hir_id ) == kw:: SelfLower && contains_ty ( cmt. place . ty ( ) , trait_self_ty) {
177+ return ;
178+ }
179+ }
180+
156181 if is_non_trait_box ( cmt. place . ty ( ) ) && !self . is_large_box ( cmt. place . ty ( ) ) {
157182 self . set . insert ( cmt. hir_id ) ;
158183 }
0 commit comments