From 35b5daaaf8ab7675c940687c0898fb4d0300c850 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Thu, 27 Jan 2022 00:00:00 +0000 Subject: [PATCH] Check the number of arguments first in `is_recursive_call` --- compiler/rustc_mir_build/src/lints.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs index b21ca6028a22..bccff3798734 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -66,8 +66,14 @@ struct Search<'mir, 'tcx> { impl<'mir, 'tcx> Search<'mir, 'tcx> { /// Returns `true` if `func` refers to the function we are searching in. - fn is_recursive_call(&self, func: &Operand<'tcx>) -> bool { + fn is_recursive_call(&self, func: &Operand<'tcx>, args: &[Operand<'tcx>]) -> bool { let Search { tcx, body, trait_substs, .. } = *self; + // Resolving function type to a specific instance that is being called is expensive. To + // avoid the cost we check the number of arguments first, which is sufficient to reject + // most of calls as non-recursive. + if args.len() != body.arg_count { + return false; + } let caller = body.source.def_id(); let param_env = tcx.param_env(caller); @@ -141,8 +147,8 @@ impl<'mir, 'tcx> TriColorVisitor<&'mir Body<'tcx>> for Search<'mir, 'tcx> { fn node_settled(&mut self, bb: BasicBlock) -> ControlFlow { // When we examine a node for the last time, remember it if it is a recursive call. let terminator = self.body[bb].terminator(); - if let TerminatorKind::Call { func, .. } = &terminator.kind { - if self.is_recursive_call(func) { + if let TerminatorKind::Call { func, args, .. } = &terminator.kind { + if self.is_recursive_call(func, args) { self.reachable_recursive_calls.push(terminator.source_info.span); } } @@ -157,7 +163,7 @@ impl<'mir, 'tcx> TriColorVisitor<&'mir Body<'tcx>> for Search<'mir, 'tcx> { } // Don't traverse successors of recursive calls or false CFG edges. match self.body[bb].terminator().kind { - TerminatorKind::Call { ref func, .. } => self.is_recursive_call(func), + TerminatorKind::Call { ref func, ref args, .. } => self.is_recursive_call(func, args), TerminatorKind::FalseEdge { imaginary_target, .. } => imaginary_target == target, _ => false, }