1
1
use 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 } ;
3
3
use rustc_infer:: infer:: TyCtxtInferExt ;
4
4
use rustc_lint:: { LateContext , LateLintPass } ;
5
- use rustc_middle:: ty:: { self , Ty } ;
5
+ use rustc_middle:: ty:: { self , TraitRef , Ty } ;
6
6
use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
7
7
use rustc_span:: source_map:: Span ;
8
+ use rustc_span:: symbol:: kw;
8
9
use rustc_target:: abi:: LayoutOf ;
9
10
use rustc_target:: spec:: abi:: Abi ;
10
11
use rustc_typeck:: expr_use_visitor:: { ConsumeMode , Delegate , ExprUseVisitor , PlaceBase , PlaceWithHirId } ;
11
12
12
- use crate :: utils:: span_lint;
13
+ use crate :: utils:: { contains_ty , span_lint} ;
13
14
14
15
#[ derive( Copy , Clone ) ]
15
16
pub struct BoxedLocal {
@@ -51,6 +52,7 @@ fn is_non_trait_box(ty: Ty<'_>) -> bool {
51
52
struct EscapeDelegate < ' a , ' tcx > {
52
53
cx : & ' a LateContext < ' tcx > ,
53
54
set : HirIdSet ,
55
+ trait_self_ty : Option < Ty < ' a > > ,
54
56
too_large_for_stack : u64 ,
55
57
}
56
58
@@ -72,19 +74,34 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal {
72
74
}
73
75
}
74
76
75
- // If the method is an impl for a trait, don't warn.
76
77
let parent_id = cx. tcx . hir ( ) . get_parent_item ( hir_id) ;
77
78
let parent_node = cx. tcx . hir ( ) . find ( parent_id) ;
78
79
80
+ let mut trait_self_ty = None ;
79
81
if let Some ( Node :: Item ( item) ) = parent_node {
82
+ // If the method is an impl for a trait, don't warn.
80
83
if let ItemKind :: Impl { of_trait : Some ( _) , .. } = item. kind {
81
84
return ;
82
85
}
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
+ }
83
99
}
84
100
85
101
let mut v = EscapeDelegate {
86
102
cx,
87
103
set : HirIdSet :: default ( ) ,
104
+ trait_self_ty,
88
105
too_large_for_stack : self . too_large_for_stack ,
89
106
} ;
90
107
@@ -153,6 +170,14 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
153
170
return ;
154
171
}
155
172
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
+
156
181
if is_non_trait_box ( cmt. place . ty ( ) ) && !self . is_large_box ( cmt. place . ty ( ) ) {
157
182
self . set . insert ( cmt. hir_id ) ;
158
183
}
0 commit comments