Skip to content

Commit 5829b8c

Browse files
committed
Make unconditional_recursion warning detect recursive drops
1 parent eed34b8 commit 5829b8c

File tree

3 files changed

+58
-4
lines changed

3 files changed

+58
-4
lines changed

compiler/rustc_mir_build/src/lints.rs

+39-3
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ use rustc_data_structures::graph::iterate::{
33
NodeStatus, TriColorDepthFirstSearch, TriColorVisitor,
44
};
55
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};
810
use rustc_middle::ty::{GenericArg, GenericArgs};
911
use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION;
1012
use 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

5984
impl<'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

103139
impl<'mir, 'tcx> TriColorVisitor<BasicBlocks<'tcx>> for Search<'mir, 'tcx> {

tests/ui/lint/lint-unconditional-recursion.rs

+8
Original file line numberDiff line numberDiff line change
@@ -191,4 +191,12 @@ impl Default for Point {
191191
}
192192
}
193193

194+
pub struct RecursiveDrop;
195+
196+
impl Drop for RecursiveDrop {
197+
fn drop(&mut self) { //~ ERROR function cannot return without recursing
198+
let _ = RecursiveDrop;
199+
}
200+
}
201+
194202
fn main() {}

tests/ui/lint/lint-unconditional-recursion.stderr

+11-1
Original file line numberDiff line numberDiff line change
@@ -197,5 +197,15 @@ LL | ..Default::default()
197197
|
198198
= help: a `loop` may express intention better if this is on purpose
199199

200-
error: aborting due to 18 previous errors
200+
error: function cannot return without recursing
201+
--> $DIR/lint-unconditional-recursion.rs:197:5
202+
|
203+
LL | fn drop(&mut self) {
204+
| ^^^^^^^^^^^^^^^^^^ cannot return without recursing
205+
LL | let _ = RecursiveDrop;
206+
| - recursive call site
207+
|
208+
= help: a `loop` may express intention better if this is on purpose
209+
210+
error: aborting due to 19 previous errors
201211

0 commit comments

Comments
 (0)