Skip to content

Undetected unconditional recursion in Clone impl using to_owned() #40437

Open
@crumblingstatue

Description

@crumblingstatue
fn main() {
    struct Foo;
    impl Clone for Foo {
        fn clone(&self) -> Self {
            self.to_owned()
        }
    }
    Foo.clone();
}

Rustc gives no warning, but this overflows the stack.

Slightly more realistic example:

fn main() {
    use std::borrow::{Borrow, ToOwned};
    use std::ops::Deref;
    struct Foo;
    struct Borrowed;
    impl Deref for Foo {
        type Target = Borrowed;
        fn deref(&self) -> &Borrowed {
            unimplemented!()
        }
    }
    impl Borrow<Borrowed> for Foo {
        fn borrow(&self) -> &Borrowed {
            &*self
        }
    }
    impl ToOwned for Borrowed {
        type Owned = Foo;
        fn to_owned(&self) -> Foo {
            unimplemented!()
        }
    }
    impl Clone for Foo {
        fn clone(&self) -> Self {
            (*self).to_owned() // Oops, should have dereferenced twice
        }
    }
    Foo.clone();
}

(Real life use case for implementing Clone through deref -> to_owned)

Is it feasible for rustc to detect this kind of cross-trait unconditional recursion?

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.C-enhancementCategory: An issue proposing an enhancement or a PR with one.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions