From b1931e48a01b418b4b1ba6c747f2c99a5b10d96f Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Mon, 29 Jun 2015 14:51:56 -0700 Subject: [PATCH 1/2] lint: only consider actual calls as unconditional recursion. Specifically, just mentioning the function name as a value is fine, as long as it isn't called, e.g. `fn main() { let _ = main; }`. Closes #21705. --- src/librustc_lint/builtin.rs | 9 +++++++-- src/test/compile-fail/lint-unconditional-recursion.rs | 4 ++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index db48608823d21..3d5eb422b634b 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1973,8 +1973,13 @@ impl LintPass for UnconditionalRecursion { fn_id: ast::NodeId, _: ast::Ident, id: ast::NodeId) -> bool { - tcx.def_map.borrow().get(&id) - .map_or(false, |def| def.def_id() == local_def(fn_id)) + match tcx.map.get(id) { + ast_map::NodeExpr(&ast::Expr { node: ast::ExprCall(ref callee, _), .. }) => { + tcx.def_map.borrow().get(&callee.id) + .map_or(false, |def| def.def_id() == local_def(fn_id)) + } + _ => false + } } // check if the method call `id` refers to method `method_id` diff --git a/src/test/compile-fail/lint-unconditional-recursion.rs b/src/test/compile-fail/lint-unconditional-recursion.rs index 0c3d1c6adea40..0cd71aebd63fb 100644 --- a/src/test/compile-fail/lint-unconditional-recursion.rs +++ b/src/test/compile-fail/lint-unconditional-recursion.rs @@ -63,4 +63,8 @@ impl Baz { } } +fn all_fine() { + let _f = all_fine; +} + fn main() {} From 900af2c6d9b21ca1b1db35b7b09b0fb59cf78b84 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Mon, 29 Jun 2015 15:56:00 -0700 Subject: [PATCH 2/2] lint: default methods must be called on Self to unconditionally recur. This catches the case when a trait defines a default method that calls itself, but on a type that isn't necessarily `Self`, e.g. there's no reason that `T = Self` in the following, so the call isn't necessarily recursive (`T` may override the call). trait Bar { fn method(&self, x: &T) { x.method(x) } } Fixes #26333. --- src/librustc_lint/builtin.rs | 9 +++++++++ src/test/compile-fail/lint-unconditional-recursion.rs | 7 +++++++ 2 files changed, 16 insertions(+) diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 3d5eb422b634b..190e2965e76ce 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -2007,6 +2007,15 @@ impl LintPass for UnconditionalRecursion { // method instead. ty::MethodTypeParam( ty::MethodParam { ref trait_ref, method_num, impl_def_id: None, }) => { + + let on_self = m.substs.self_ty().map_or(false, |t| t.is_self()); + if !on_self { + // we can only be recurring in a default + // method if we're being called literally + // on the `Self` type. + return false + } + tcx.trait_item(trait_ref.def_id, method_num).def_id() } diff --git a/src/test/compile-fail/lint-unconditional-recursion.rs b/src/test/compile-fail/lint-unconditional-recursion.rs index 0cd71aebd63fb..47bb7f948a786 100644 --- a/src/test/compile-fail/lint-unconditional-recursion.rs +++ b/src/test/compile-fail/lint-unconditional-recursion.rs @@ -67,4 +67,11 @@ fn all_fine() { let _f = all_fine; } +// issue 26333 +trait Bar { + fn method(&self, x: &T) { + x.method(x) + } +} + fn main() {}