rust-lang / rust-clippy

A bunch of lints to catch common mistakes and improve your Rust code. Book: https://doc.rust-lang.org/clippy/
https://rust-lang.github.io/rust-clippy/
Other
11.48k stars 1.55k forks source link

Eternal lint on a recursive tree #13544

Open cyypherus opened 1 month ago

cyypherus commented 1 month ago

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

y21 commented 1 month ago

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> ...).

c410-f3r commented 1 month ago

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