Eternal lint on a recursive tree
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
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> ...).
Sigh... There are many errors related to significant_drop_tightening. I hope to get back to working on it in the coming weeks.
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)
For y21's code:
cargo clippystill hangs on stable rust 1.86.0cargo clippyworks 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.
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)
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 😃
For the record, the code by
@theemathasabove triggered a bug in an unrelated util function (used in thelarge_enum_variantslint) 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.