rust-clippy icon indicating copy to clipboard operation
rust-clippy copied to clipboard

Eternal lint on a recursive tree

Open cyypherus opened this issue 1 year ago • 2 comments

Summary

This code causes clippy to hang & never complete linting.

use std::mem::ManuallyDrop;
use std::ops::Deref;
use std::ops::DerefMut;

trait Scopable: Sized {
    type SubType: Scopable;
}

struct Subtree<T: Scopable>(ManuallyDrop<Box<Tree<T::SubType>>>);

impl<T: Scopable> Drop for Subtree<T> {
    fn drop(&mut self) {
        // SAFETY: The field cannot be used after we drop
        unsafe { ManuallyDrop::drop(&mut self.0) }
    }
}

impl<T: Scopable> Deref for Subtree<T> {
    type Target = Tree<T::SubType>;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<T: Scopable> DerefMut for Subtree<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

enum Tree<T: Scopable> {
    Group(Vec<Tree<T>>),
    Subtree(Subtree<T>),
    Leaf(T),
}

impl<T: Scopable> Tree<T> {
    fn foo(self) -> Self {
        self
    }
}

fn main() {}

Reproducer

I tried this code:(See above)

I expected to see this happen: Clippy finish linting within a reasonable time period

Instead, this happened: Clippy doesn't finish linting & hangs, eating 90% cpu

Version

rustc 1.83.0-nightly (1bc403daa 2024-10-11) binary: rustc commit-hash: 1bc403daadbebb553ccc211a0a8eebb73989665f commit-date: 2024-10-11 host: aarch64-apple-darwin release: 1.83.0-nightly LLVM version: 19.1.1

Additional Labels

No response

cyypherus avatar Oct 13 '24 01:10 cyypherus

Looks like a hang in the significant_drop_tightening lint. Reduced a bit further:

use std::marker::PhantomData;

trait Trait {
    type Assoc: Trait;
}
struct S<T: Trait>(*const S<T::Assoc>, PhantomData<T>);

fn f<T: Trait>(x: &mut S<T>) {
    &mut x.0;
}

fn main() {}

We keep recursing into the first field of the struct and always miss the type cache because each level of nesting adds another projection (S<T::Assoc> -> S<T::Assoc::Assoc> -> S<T::Assoc::Assoc::Assoc> ...).

y21 avatar Oct 13 '24 03:10 y21

Sigh... There are many errors related to significant_drop_tightening. I hope to get back to working on it in the coming weeks.

c410-f3r avatar Oct 13 '24 22:10 c410-f3r

The below code causes cargo clippy to hang in rust version 1.86.0, but cargo clippy works fine for version 1.87.0-beta.3.

trait Bar {
    type Element: Bar;
}

enum Foo<T: Bar> {
    A(*const Foo<T::Element>),
    B(T),
}

(In addition, it causes rustdoc to hang. See https://github.com/rust-lang/rust/issues/139964)

theemathas avatar Apr 17 '25 10:04 theemathas

For y21's code:

  • cargo clippy still hangs on stable rust 1.86.0
  • cargo clippy works fine on beta rust 1.87.0-beta.3, but adding #![warn(clippy::significant_drop_tightening)] causes it to hang again

Adding #![warn(clippy::significant_drop_tightening)] appears to have no effect on my code.

theemathas avatar Apr 17 '25 10:04 theemathas

For the record, the code by @theemathas above triggered a bug in an unrelated util function (used in the large_enum_variants lint) and was fixed by #13833, where a general recursion limit was added to that function.

The code in the OP (and my reproducer) triggers a different bug in significant_drop_tightening, which is why #![warn(significant_drop_tightening)] is needed for specifically only those two (the lint is in nursery so would normally be filtered out and the buggy code doesn't run).

I imagine this issue could probably be fixed in the same way as the other issue was fixed (just bail if we recurse too much in this function, which is where the stack overflow/hang happens, and conservatively return false)

y21 avatar Apr 17 '25 11:04 y21

I imagine this issue could probably be fixed in the same way as the other issue was fixed (just bail if we recurse too much in this function, which is where the stack overflow/hang happens, and conservatively return false)

Indeed, done this way in #14641 a few minutes ago while you were writing this message, and assigned to you for review 😃

samueltardieu avatar Apr 17 '25 11:04 samueltardieu

For the record, the code by @theemathas above triggered a bug in an unrelated util function (used in the large_enum_variants lint) and was fixed by #13833, where a general recursion limit was added to that function.

And the PR missed the Clippy sync by one day, which made it miss master→1.86, which is why it will be present only in 1.87.

samueltardieu avatar Apr 17 '25 11:04 samueltardieu