@@ -3,8 +3,10 @@ use rustc_data_structures::graph::iterate::{
33 NodeStatus , TriColorDepthFirstSearch , TriColorVisitor ,
44} ;
55use 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 } ;
810use rustc_middle:: ty:: { GenericArg , GenericArgs } ;
911use rustc_session:: lint:: builtin:: UNCONDITIONAL_RECURSION ;
1012use rustc_span:: Span ;
@@ -23,7 +25,26 @@ pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
2325 _ => & [ ] ,
2426 } ;
2527
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 } ;
2748 if let Some ( NonRecursive ) =
2849 TriColorDepthFirstSearch :: new ( & body. basic_blocks ) . run_from_start ( & mut vis)
2950 {
@@ -53,13 +74,18 @@ struct Search<'mir, 'tcx> {
5374 body : & ' mir Body < ' tcx > ,
5475 trait_args : & ' tcx [ GenericArg < ' tcx > ] ,
5576
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+
5681 reachable_recursive_calls : Vec < Span > ,
5782}
5883
5984impl < ' mir , ' tcx > Search < ' mir , ' tcx > {
6085 fn is_recursive_terminator ( & self , terminator : & Terminator < ' tcx > ) -> bool {
6186 match & terminator. kind {
6287 TerminatorKind :: Call { func, args, .. } => self . is_recursive_call ( func, args) ,
88+ TerminatorKind :: Drop { place, .. } => self . is_recursive_drop ( place) ,
6389 _ => false ,
6490 }
6591 }
@@ -98,6 +124,16 @@ impl<'mir, 'tcx> Search<'mir, 'tcx> {
98124
99125 false
100126 }
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+ }
101137}
102138
103139impl < ' mir , ' tcx > TriColorVisitor < BasicBlocks < ' tcx > > for Search < ' mir , ' tcx > {
0 commit comments