11use crate :: FxHashSet ;
22use clippy_utils:: diagnostics:: span_lint_and_then;
3- use clippy_utils:: get_attr;
43use clippy_utils:: source:: { indent_of, snippet} ;
4+ use clippy_utils:: { get_attr, is_lint_allowed} ;
55use rustc_errors:: { Applicability , Diagnostic } ;
66use rustc_hir:: intravisit:: { walk_expr, Visitor } ;
7- use rustc_hir:: { Expr , ExprKind , MatchSource } ;
7+ use rustc_hir:: { Arm , Expr , ExprKind , MatchSource } ;
88use rustc_lint:: { LateContext , LintContext } ;
99use rustc_middle:: ty:: subst:: GenericArgKind ;
1010use rustc_middle:: ty:: { Ty , TypeAndMut } ;
@@ -16,12 +16,23 @@ pub(super) fn check<'tcx>(
1616 cx : & LateContext < ' tcx > ,
1717 expr : & ' tcx Expr < ' tcx > ,
1818 scrutinee : & ' tcx Expr < ' _ > ,
19+ arms : & ' tcx [ Arm < ' _ > ] ,
1920 source : MatchSource ,
2021) {
22+ if is_lint_allowed ( cx, SIGNIFICANT_DROP_IN_SCRUTINEE , expr. hir_id ) {
23+ return ;
24+ }
25+
2126 if let Some ( ( suggestions, message) ) = has_significant_drop_in_scrutinee ( cx, scrutinee, source) {
2227 for found in suggestions {
2328 span_lint_and_then ( cx, SIGNIFICANT_DROP_IN_SCRUTINEE , found. found_span , message, |diag| {
2429 set_diagnostic ( diag, cx, expr, found) ;
30+ let s = Span :: new ( expr. span . hi ( ) , expr. span . hi ( ) , expr. span . ctxt ( ) , None ) ;
31+ diag. span_label ( s, "temporary lives until here" ) ;
32+ for span in has_significant_drop_in_arms ( cx, arms) {
33+ diag. span_label ( span, "another value with significant `Drop` created here" ) ;
34+ }
35+ diag. note ( "this might lead to deadlocks or other unexpected behavior" ) ;
2536 } ) ;
2637 }
2738 }
@@ -80,22 +91,77 @@ fn has_significant_drop_in_scrutinee<'tcx, 'a>(
8091 let mut helper = SigDropHelper :: new ( cx) ;
8192 helper. find_sig_drop ( scrutinee) . map ( |drops| {
8293 let message = if source == MatchSource :: Normal {
83- "temporary with significant drop in match scrutinee"
94+ "temporary with significant `Drop` in ` match` scrutinee will live until the end of the `match` expression "
8495 } else {
85- "temporary with significant drop in for loop"
96+ "temporary with significant `Drop` in ` for` loop condition will live until the end of the `for` expression "
8697 } ;
8798 ( drops, message)
8899 } )
89100}
90101
102+ struct SigDropChecker < ' a , ' tcx > {
103+ seen_types : FxHashSet < Ty < ' tcx > > ,
104+ cx : & ' a LateContext < ' tcx > ,
105+ }
106+
107+ impl < ' a , ' tcx > SigDropChecker < ' a , ' tcx > {
108+ fn new ( cx : & ' a LateContext < ' tcx > ) -> SigDropChecker < ' a , ' tcx > {
109+ SigDropChecker {
110+ seen_types : FxHashSet :: default ( ) ,
111+ cx,
112+ }
113+ }
114+
115+ fn get_type ( & self , ex : & ' tcx Expr < ' _ > ) -> Ty < ' tcx > {
116+ self . cx . typeck_results ( ) . expr_ty ( ex)
117+ }
118+
119+ fn has_seen_type ( & mut self , ty : Ty < ' tcx > ) -> bool {
120+ !self . seen_types . insert ( ty)
121+ }
122+
123+ fn has_sig_drop_attr ( & mut self , cx : & LateContext < ' tcx > , ty : Ty < ' tcx > ) -> bool {
124+ if let Some ( adt) = ty. ty_adt_def ( ) {
125+ if get_attr ( cx. sess ( ) , cx. tcx . get_attrs_unchecked ( adt. did ( ) ) , "has_significant_drop" ) . count ( ) > 0 {
126+ return true ;
127+ }
128+ }
129+
130+ match ty. kind ( ) {
131+ rustc_middle:: ty:: Adt ( a, b) => {
132+ for f in a. all_fields ( ) {
133+ let ty = f. ty ( cx. tcx , b) ;
134+ if !self . has_seen_type ( ty) && self . has_sig_drop_attr ( cx, ty) {
135+ return true ;
136+ }
137+ }
138+
139+ for generic_arg in b. iter ( ) {
140+ if let GenericArgKind :: Type ( ty) = generic_arg. unpack ( ) {
141+ if self . has_sig_drop_attr ( cx, ty) {
142+ return true ;
143+ }
144+ }
145+ }
146+ false
147+ } ,
148+ rustc_middle:: ty:: Array ( ty, _)
149+ | rustc_middle:: ty:: RawPtr ( TypeAndMut { ty, .. } )
150+ | rustc_middle:: ty:: Ref ( _, ty, _)
151+ | rustc_middle:: ty:: Slice ( ty) => self . has_sig_drop_attr ( cx, * ty) ,
152+ _ => false ,
153+ }
154+ }
155+ }
156+
91157struct SigDropHelper < ' a , ' tcx > {
92158 cx : & ' a LateContext < ' tcx > ,
93159 is_chain_end : bool ,
94- seen_types : FxHashSet < Ty < ' tcx > > ,
95160 has_significant_drop : bool ,
96161 current_sig_drop : Option < FoundSigDrop > ,
97162 sig_drop_spans : Option < Vec < FoundSigDrop > > ,
98163 special_handling_for_binary_op : bool ,
164+ sig_drop_checker : SigDropChecker < ' a , ' tcx > ,
99165}
100166
101167#[ expect( clippy:: enum_variant_names) ]
@@ -118,11 +184,11 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> {
118184 SigDropHelper {
119185 cx,
120186 is_chain_end : true ,
121- seen_types : FxHashSet :: default ( ) ,
122187 has_significant_drop : false ,
123188 current_sig_drop : None ,
124189 sig_drop_spans : None ,
125190 special_handling_for_binary_op : false ,
191+ sig_drop_checker : SigDropChecker :: new ( cx) ,
126192 }
127193 }
128194
@@ -163,7 +229,7 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> {
163229 if self . current_sig_drop . is_some ( ) {
164230 return ;
165231 }
166- let ty = self . get_type ( expr) ;
232+ let ty = self . sig_drop_checker . get_type ( expr) ;
167233 if ty. is_ref ( ) {
168234 // We checked that the type was ref, so builtin_deref will return Some TypeAndMut,
169235 // but let's avoid any chance of an ICE
@@ -187,14 +253,6 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> {
187253 }
188254 }
189255
190- fn get_type ( & self , ex : & ' tcx Expr < ' _ > ) -> Ty < ' tcx > {
191- self . cx . typeck_results ( ) . expr_ty ( ex)
192- }
193-
194- fn has_seen_type ( & mut self , ty : Ty < ' tcx > ) -> bool {
195- !self . seen_types . insert ( ty)
196- }
197-
198256 fn visit_exprs_for_binary_ops (
199257 & mut self ,
200258 left : & ' tcx Expr < ' _ > ,
@@ -214,44 +272,15 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> {
214272
215273 self . special_handling_for_binary_op = false ;
216274 }
217-
218- fn has_sig_drop_attr ( & mut self , cx : & LateContext < ' tcx > , ty : Ty < ' tcx > ) -> bool {
219- if let Some ( adt) = ty. ty_adt_def ( ) {
220- if get_attr ( cx. sess ( ) , cx. tcx . get_attrs_unchecked ( adt. did ( ) ) , "has_significant_drop" ) . count ( ) > 0 {
221- return true ;
222- }
223- }
224-
225- match ty. kind ( ) {
226- rustc_middle:: ty:: Adt ( a, b) => {
227- for f in a. all_fields ( ) {
228- let ty = f. ty ( cx. tcx , b) ;
229- if !self . has_seen_type ( ty) && self . has_sig_drop_attr ( cx, ty) {
230- return true ;
231- }
232- }
233-
234- for generic_arg in b. iter ( ) {
235- if let GenericArgKind :: Type ( ty) = generic_arg. unpack ( ) {
236- if self . has_sig_drop_attr ( cx, ty) {
237- return true ;
238- }
239- }
240- }
241- false
242- } ,
243- rustc_middle:: ty:: Array ( ty, _)
244- | rustc_middle:: ty:: RawPtr ( TypeAndMut { ty, .. } )
245- | rustc_middle:: ty:: Ref ( _, ty, _)
246- | rustc_middle:: ty:: Slice ( ty) => self . has_sig_drop_attr ( cx, * ty) ,
247- _ => false ,
248- }
249- }
250275}
251276
252277impl < ' a , ' tcx > Visitor < ' tcx > for SigDropHelper < ' a , ' tcx > {
253278 fn visit_expr ( & mut self , ex : & ' tcx Expr < ' _ > ) {
254- if !self . is_chain_end && self . has_sig_drop_attr ( self . cx , self . get_type ( ex) ) {
279+ if !self . is_chain_end
280+ && self
281+ . sig_drop_checker
282+ . has_sig_drop_attr ( self . cx , self . sig_drop_checker . get_type ( ex) )
283+ {
255284 self . has_significant_drop = true ;
256285 return ;
257286 }
@@ -330,3 +359,38 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
330359 }
331360 }
332361}
362+
363+ struct ArmSigDropHelper < ' a , ' tcx > {
364+ sig_drop_checker : SigDropChecker < ' a , ' tcx > ,
365+ found_sig_drop_spans : FxHashSet < Span > ,
366+ }
367+
368+ impl < ' a , ' tcx > ArmSigDropHelper < ' a , ' tcx > {
369+ fn new ( cx : & ' a LateContext < ' tcx > ) -> ArmSigDropHelper < ' a , ' tcx > {
370+ ArmSigDropHelper {
371+ sig_drop_checker : SigDropChecker :: new ( cx) ,
372+ found_sig_drop_spans : FxHashSet :: < Span > :: default ( ) ,
373+ }
374+ }
375+ }
376+
377+ fn has_significant_drop_in_arms < ' tcx , ' a > ( cx : & ' a LateContext < ' tcx > , arms : & ' tcx [ Arm < ' _ > ] ) -> FxHashSet < Span > {
378+ let mut helper = ArmSigDropHelper :: new ( cx) ;
379+ for arm in arms {
380+ helper. visit_expr ( arm. body ) ;
381+ }
382+ helper. found_sig_drop_spans
383+ }
384+
385+ impl < ' a , ' tcx > Visitor < ' tcx > for ArmSigDropHelper < ' a , ' tcx > {
386+ fn visit_expr ( & mut self , ex : & ' tcx Expr < ' tcx > ) {
387+ if self
388+ . sig_drop_checker
389+ . has_sig_drop_attr ( self . sig_drop_checker . cx , self . sig_drop_checker . get_type ( ex) )
390+ {
391+ self . found_sig_drop_spans . insert ( ex. span ) ;
392+ return ;
393+ }
394+ walk_expr ( self , ex) ;
395+ }
396+ }
0 commit comments