@@ -3,8 +3,10 @@ use rustc_data_structures::graph::iterate::{
3
3
NodeStatus , TriColorDepthFirstSearch , TriColorVisitor ,
4
4
} ;
5
5
use rustc_hir:: def:: DefKind ;
6
- use rustc_middle:: mir:: { self , BasicBlock , BasicBlocks , Body , Operand , Terminator , TerminatorKind } ;
7
- use rustc_middle:: ty:: { self , Instance , TyCtxt } ;
6
+ use rustc_middle:: mir:: {
7
+ self , BasicBlock , BasicBlocks , Body , Operand , Place , Terminator , TerminatorKind ,
8
+ } ;
9
+ use rustc_middle:: ty:: { self , Instance , Ty , TyCtxt } ;
8
10
use rustc_middle:: ty:: { GenericArg , GenericArgs } ;
9
11
use rustc_session:: lint:: builtin:: UNCONDITIONAL_RECURSION ;
10
12
use rustc_span:: Span ;
@@ -23,7 +25,26 @@ pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
23
25
_ => & [ ] ,
24
26
} ;
25
27
26
- let mut vis = Search { tcx, body, reachable_recursive_calls : vec ! [ ] , trait_args } ;
28
+ // If this body is a drop fn, figure out for what type. That way we can
29
+ // later detect recursive drops.
30
+ let mut drop_for = None ;
31
+ if let Some ( trait_ref) =
32
+ tcx. impl_of_method ( def_id. to_def_id ( ) ) . and_then ( |def_id| tcx. impl_trait_ref ( def_id) ) &&
33
+ let Some ( drop_trait) = tcx. lang_items ( ) . drop_trait ( ) &&
34
+ drop_trait == trait_ref. instantiate_identity ( ) . def_id
35
+ {
36
+ if let ty:: Ref ( _, dropped_ty, _) = tcx
37
+ . liberate_late_bound_regions (
38
+ def_id. to_def_id ( ) ,
39
+ tcx. fn_sig ( def_id) . instantiate_identity ( ) . input ( 0 ) ,
40
+ )
41
+ . kind ( )
42
+ {
43
+ drop_for = Some ( * dropped_ty) ;
44
+ }
45
+ } ;
46
+
47
+ let mut vis = Search { tcx, body, drop_for, reachable_recursive_calls : vec ! [ ] , trait_args } ;
27
48
if let Some ( NonRecursive ) =
28
49
TriColorDepthFirstSearch :: new ( & body. basic_blocks ) . run_from_start ( & mut vis)
29
50
{
@@ -53,13 +74,18 @@ struct Search<'mir, 'tcx> {
53
74
body : & ' mir Body < ' tcx > ,
54
75
trait_args : & ' tcx [ GenericArg < ' tcx > ] ,
55
76
77
+ // If Some, the `body` is the body of a fn drop() implementation, and the
78
+ // type is the type that Drop is implemented for
79
+ drop_for : Option < Ty < ' tcx > > ,
80
+
56
81
reachable_recursive_calls : Vec < Span > ,
57
82
}
58
83
59
84
impl < ' mir , ' tcx > Search < ' mir , ' tcx > {
60
85
fn is_recursive_terminator ( & self , terminator : & Terminator < ' tcx > ) -> bool {
61
86
match & terminator. kind {
62
87
TerminatorKind :: Call { func, args, .. } => self . is_recursive_call ( func, args) ,
88
+ TerminatorKind :: Drop { place, .. } => self . is_recursive_drop ( place) ,
63
89
_ => false ,
64
90
}
65
91
}
@@ -98,6 +124,16 @@ impl<'mir, 'tcx> Search<'mir, 'tcx> {
98
124
99
125
false
100
126
}
127
+
128
+ fn is_recursive_drop ( & self , place : & Place < ' tcx > ) -> bool {
129
+ match self . drop_for {
130
+ None => false ,
131
+ Some ( drop_for) => {
132
+ let dropped_ty = place. ty ( self . body , self . tcx ) . ty ;
133
+ dropped_ty == drop_for
134
+ }
135
+ }
136
+ }
101
137
}
102
138
103
139
impl < ' mir , ' tcx > TriColorVisitor < BasicBlocks < ' tcx > > for Search < ' mir , ' tcx > {
0 commit comments