Skip to content

Add lint for direct recursive self-call of function #17899

Closed
@huonw

Description

@huonw

With trait objects it is not so rare to have code like

impl Foo for Box<Foo> {
    fn bar(&self, x: uint) {
        // call the `bar` method in the vtable, could try:
        // self.bar(x);
        // (*self).bar(x);
        // (**self).bar(x);
    }
}

One might first write self.bar(x), but this will be calling that same bar, via since Box<Foo> has a "real" bar method itself. The correct procedure is (**self).bar(x). This would helped by detecting the most obvious cases of a function calling itself in a nonterminating way. The most obvious way that is likely to have low risk of false positives is detecting if the CFG of a function reaches a self-call unconditionally. e.g.

// these receive a warning:
fn foo() { foo() }

fn bar(x: uint) {
    bar(x - 1);
}

fn baz(x: uint) -> uint {
    if x == 0 {
        println!("hi")
    }
    2 * baz(x + 1)
}

// this is fine:
fn qux(x: uint) {
    if x == 0 { loop {} } // (could be `return 1`, etc. etc.)

    qux(x - 1) + 1
}

Notably, it does not matter if the arguments to the self call are different, since the call will always occur, and it also does not matter if the self-call is in tail position.

There is the possibility that someone is using infinite recursion to achieve an infinite loop, it doesn't seem crazy to recommend that they use loop instead.

A more conservative alternative would be just detecting the method call in the first example, that is, a function that consists of a single expression that is a self-call.

Metadata

Metadata

Assignees

Labels

A-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions