2023-12-08 17:12:32 -06:00
|
|
|
//@no-rustfix
|
|
|
|
|
|
|
|
#![warn(clippy::unconditional_recursion)]
|
2024-03-10 14:40:31 -05:00
|
|
|
#![allow(
|
|
|
|
clippy::partialeq_ne_impl,
|
|
|
|
clippy::default_constructed_unit_structs,
|
2024-08-18 06:31:47 -05:00
|
|
|
clippy::only_used_in_recursion,
|
|
|
|
clippy::needless_lifetimes
|
2024-03-10 14:40:31 -05:00
|
|
|
)]
|
2023-12-08 17:12:32 -06:00
|
|
|
|
|
|
|
enum Foo {
|
|
|
|
A,
|
|
|
|
B,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PartialEq for Foo {
|
|
|
|
fn ne(&self, other: &Self) -> bool {
|
|
|
|
//~^ ERROR: function cannot return without recursing
|
|
|
|
self != other
|
|
|
|
}
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
//~^ ERROR: function cannot return without recursing
|
|
|
|
self == other
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
enum Foo2 {
|
|
|
|
A,
|
|
|
|
B,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PartialEq for Foo2 {
|
|
|
|
fn ne(&self, other: &Self) -> bool {
|
|
|
|
self != &Foo2::B // no error here
|
|
|
|
}
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
self == &Foo2::B // no error here
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
enum Foo3 {
|
|
|
|
A,
|
|
|
|
B,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PartialEq for Foo3 {
|
|
|
|
fn ne(&self, other: &Self) -> bool {
|
|
|
|
//~^ ERROR: function cannot return without recursing
|
|
|
|
self.ne(other)
|
|
|
|
}
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
//~^ ERROR: function cannot return without recursing
|
|
|
|
self.eq(other)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
enum Foo4 {
|
|
|
|
A,
|
|
|
|
B,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PartialEq for Foo4 {
|
|
|
|
fn ne(&self, other: &Self) -> bool {
|
|
|
|
self.eq(other) // no error
|
|
|
|
}
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
self.ne(other) // no error
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
enum Foo5 {
|
|
|
|
A,
|
|
|
|
B,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Foo5 {
|
|
|
|
fn a(&self) -> bool {
|
|
|
|
true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PartialEq for Foo5 {
|
|
|
|
fn ne(&self, other: &Self) -> bool {
|
|
|
|
self.a() // no error
|
|
|
|
}
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
self.a() // no error
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct S;
|
|
|
|
|
|
|
|
// Check the order doesn't matter.
|
|
|
|
impl PartialEq for S {
|
|
|
|
fn ne(&self, other: &Self) -> bool {
|
|
|
|
//~^ ERROR: function cannot return without recursing
|
|
|
|
other != self
|
|
|
|
}
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
//~^ ERROR: function cannot return without recursing
|
|
|
|
other == self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct S2;
|
|
|
|
|
|
|
|
// Check that if the same element is compared, it's also triggering the lint.
|
|
|
|
impl PartialEq for S2 {
|
|
|
|
fn ne(&self, other: &Self) -> bool {
|
|
|
|
//~^ ERROR: function cannot return without recursing
|
|
|
|
other != other
|
|
|
|
}
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
//~^ ERROR: function cannot return without recursing
|
|
|
|
other == other
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct S3;
|
|
|
|
|
|
|
|
impl PartialEq for S3 {
|
|
|
|
fn ne(&self, _other: &Self) -> bool {
|
|
|
|
//~^ ERROR: function cannot return without recursing
|
|
|
|
self != self
|
|
|
|
}
|
|
|
|
fn eq(&self, _other: &Self) -> bool {
|
|
|
|
//~^ ERROR: function cannot return without recursing
|
|
|
|
self == self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-16 11:15:32 -06:00
|
|
|
// There should be no warning here!
|
|
|
|
#[derive(PartialEq)]
|
|
|
|
enum E {
|
|
|
|
A,
|
|
|
|
B,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(PartialEq)]
|
|
|
|
struct Bar<T: PartialEq>(T);
|
|
|
|
|
|
|
|
struct S4;
|
|
|
|
|
|
|
|
impl PartialEq for S4 {
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
// No warning here.
|
|
|
|
Bar(self) == Bar(other)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
macro_rules! impl_partial_eq {
|
|
|
|
($ty:ident) => {
|
|
|
|
impl PartialEq for $ty {
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
2024-02-27 07:34:01 -06:00
|
|
|
//~^ ERROR: function cannot return without recursing
|
2023-12-16 11:15:32 -06:00
|
|
|
self == other
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
struct S5;
|
|
|
|
|
|
|
|
impl_partial_eq!(S5);
|
|
|
|
|
2023-12-31 04:01:47 -06:00
|
|
|
struct S6 {
|
|
|
|
field: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PartialEq for S6 {
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
let mine = &self.field;
|
|
|
|
let theirs = &other.field;
|
|
|
|
mine == theirs // Should not warn!
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct S7<'a> {
|
|
|
|
field: &'a S7<'a>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> PartialEq for S7<'a> {
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
//~^ ERROR: function cannot return without recursing
|
|
|
|
let mine = &self.field;
|
|
|
|
let theirs = &other.field;
|
|
|
|
mine == theirs
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct S8 {
|
|
|
|
num: i32,
|
|
|
|
field: Option<Box<S8>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PartialEq for S8 {
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
if self.num != other.num {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
let (this, other) = match (self.field.as_deref(), other.field.as_deref()) {
|
|
|
|
(Some(x1), Some(x2)) => (x1, x2),
|
|
|
|
(None, None) => return true,
|
|
|
|
_ => return false,
|
|
|
|
};
|
|
|
|
|
|
|
|
this == other
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct S9;
|
2023-12-18 09:44:07 -06:00
|
|
|
|
2024-01-10 17:52:20 -06:00
|
|
|
#[allow(clippy::to_string_trait_impl)]
|
2023-12-31 04:01:47 -06:00
|
|
|
impl std::string::ToString for S9 {
|
2023-12-18 09:44:07 -06:00
|
|
|
fn to_string(&self) -> String {
|
|
|
|
//~^ ERROR: function cannot return without recursing
|
|
|
|
self.to_string()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-31 04:01:47 -06:00
|
|
|
struct S10;
|
2023-12-18 09:44:07 -06:00
|
|
|
|
2024-01-10 17:52:20 -06:00
|
|
|
#[allow(clippy::to_string_trait_impl)]
|
2023-12-31 04:01:47 -06:00
|
|
|
impl std::string::ToString for S10 {
|
2023-12-18 09:44:07 -06:00
|
|
|
fn to_string(&self) -> String {
|
|
|
|
//~^ ERROR: function cannot return without recursing
|
|
|
|
let x = self;
|
|
|
|
x.to_string()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-31 04:01:47 -06:00
|
|
|
struct S11;
|
2023-12-18 09:44:07 -06:00
|
|
|
|
2024-01-10 17:52:20 -06:00
|
|
|
#[allow(clippy::to_string_trait_impl)]
|
2023-12-31 04:01:47 -06:00
|
|
|
impl std::string::ToString for S11 {
|
2023-12-18 09:44:07 -06:00
|
|
|
fn to_string(&self) -> String {
|
|
|
|
//~^ ERROR: function cannot return without recursing
|
|
|
|
(self as &Self).to_string()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-04 10:12:54 -06:00
|
|
|
struct S12;
|
|
|
|
|
|
|
|
impl std::default::Default for S12 {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self::new()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl S12 {
|
|
|
|
fn new() -> Self {
|
|
|
|
//~^ ERROR: function cannot return without recursing
|
|
|
|
Self::default()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn bar() -> Self {
|
|
|
|
// Should not warn!
|
|
|
|
Self::default()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Default)]
|
|
|
|
struct S13 {
|
|
|
|
f: u32,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl S13 {
|
|
|
|
fn new() -> Self {
|
2024-04-10 07:37:02 -05:00
|
|
|
// Should not warn!
|
2024-01-04 10:12:54 -06:00
|
|
|
Self::default()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-12 08:38:07 -06:00
|
|
|
struct S14 {
|
|
|
|
field: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PartialEq for S14 {
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
// Should not warn!
|
|
|
|
self.field.eq(&other.field)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct S15<'a> {
|
|
|
|
field: &'a S15<'a>,
|
2023-12-08 17:12:32 -06:00
|
|
|
}
|
2024-01-12 08:38:07 -06:00
|
|
|
|
|
|
|
impl PartialEq for S15<'_> {
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
//~^ ERROR: function cannot return without recursing
|
|
|
|
let mine = &self.field;
|
|
|
|
let theirs = &other.field;
|
|
|
|
mine.eq(theirs)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-20 13:26:06 -06:00
|
|
|
mod issue12154 {
|
|
|
|
struct MyBox<T>(T);
|
|
|
|
|
|
|
|
impl<T> std::ops::Deref for MyBox<T> {
|
|
|
|
type Target = T;
|
|
|
|
fn deref(&self) -> &T {
|
|
|
|
&self.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: PartialEq> PartialEq for MyBox<T> {
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
(**self).eq(&**other)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Not necessarily related to the issue but another FP from the http crate that was fixed with it:
|
|
|
|
// https://docs.rs/http/latest/src/http/header/name.rs.html#1424
|
|
|
|
// We used to simply peel refs from the LHS and RHS, so we couldn't differentiate
|
|
|
|
// between `PartialEq<T> for &T` and `PartialEq<&T> for T` impls.
|
|
|
|
#[derive(PartialEq)]
|
|
|
|
struct HeaderName;
|
|
|
|
impl<'a> PartialEq<&'a HeaderName> for HeaderName {
|
|
|
|
fn eq(&self, other: &&'a HeaderName) -> bool {
|
|
|
|
*self == **other
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> PartialEq<HeaderName> for &'a HeaderName {
|
|
|
|
fn eq(&self, other: &HeaderName) -> bool {
|
|
|
|
*other == *self
|
|
|
|
}
|
|
|
|
}
|
2024-01-21 06:33:03 -06:00
|
|
|
|
|
|
|
// Issue #12181 but also fixed by the same PR
|
|
|
|
struct Foo;
|
|
|
|
|
|
|
|
impl Foo {
|
|
|
|
fn as_str(&self) -> &str {
|
|
|
|
"Foo"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PartialEq for Foo {
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
self.as_str().eq(other.as_str())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> PartialEq<T> for Foo
|
|
|
|
where
|
|
|
|
for<'a> &'a str: PartialEq<T>,
|
|
|
|
{
|
|
|
|
fn eq(&self, other: &T) -> bool {
|
|
|
|
(&self.as_str()).eq(other)
|
|
|
|
}
|
|
|
|
}
|
2024-01-20 13:26:06 -06:00
|
|
|
}
|
|
|
|
|
2024-03-10 14:40:31 -05:00
|
|
|
// From::from -> Into::into -> From::from
|
|
|
|
struct BadFromTy1<'a>(&'a ());
|
|
|
|
struct BadIntoTy1<'b>(&'b ());
|
|
|
|
impl<'a> From<BadFromTy1<'a>> for BadIntoTy1<'static> {
|
|
|
|
fn from(f: BadFromTy1<'a>) -> Self {
|
|
|
|
f.into()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Using UFCS syntax
|
|
|
|
struct BadFromTy2<'a>(&'a ());
|
|
|
|
struct BadIntoTy2<'b>(&'b ());
|
|
|
|
impl<'a> From<BadFromTy2<'a>> for BadIntoTy2<'static> {
|
|
|
|
fn from(f: BadFromTy2<'a>) -> Self {
|
|
|
|
Into::into(f)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Different Into impl (<i16 as Into<i32>>), so no infinite recursion
|
|
|
|
struct BadFromTy3;
|
|
|
|
impl From<BadFromTy3> for i32 {
|
|
|
|
fn from(f: BadFromTy3) -> Self {
|
|
|
|
Into::into(1i16)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// A conditional return that ends the recursion
|
|
|
|
struct BadFromTy4;
|
|
|
|
impl From<BadFromTy4> for i32 {
|
|
|
|
fn from(f: BadFromTy4) -> Self {
|
|
|
|
if true {
|
|
|
|
return 42;
|
|
|
|
}
|
|
|
|
f.into()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Types differ in refs, don't lint
|
|
|
|
impl From<&BadFromTy4> for i32 {
|
|
|
|
fn from(f: &BadFromTy4) -> Self {
|
|
|
|
BadFromTy4.into()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-12 08:38:07 -06:00
|
|
|
fn main() {}
|