rust-lang / rust-lang/rust-clippy

Lint: Explicit destructor should necessiate not using #[derive(Clone)]

Open
#4,034 3 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
13.5k
Forks
2.2k
Avg merge
2d 10h
Merged PRs (30d)
32

Description

In C++, there is a concept called the Rule of three. It essentially means that if a class has any of those:

  • Destructor
  • Copy constructor
  • Copy assignment operator
  • Move constructor
  • Move assignment operator

It should probably all five of those.

In Rust, the user cannot redefine moves, and copy assignment operator is Clone::clone_from which has a reasonable implementation if Clone::clone is implemented correctly. Therefore, the rule could be simplified to the Rule of two. In short, if a type has either one of those two, it should implement both.

  • Drop implementation
  • non-trivial Clone implementation

Non-trivial Clone implementation is a tricky thing. #[derive(Clone)] is trivial, but so is an explicit implementation that pretty much clones or copies every field (which is sometimes necessary due to https://github.com/rust-lang/rust/issues/26925 or to implement clone_from method). Also, an implementation that is *self is trivial. Determining whether a Clone implementation is trivial may be tricky.

In my opinion, an implementation that simply constructs the same structure while copying or cloning all fields or assigning value of the same type for ZSTs should be considered trivial (it's very likely an user will type _phantom: PhantomData instead of _phantom: self._phantom which is why ZSTs should have a special exception).

Having #[derive(Clone)] with Drop implementation is almost certainly a mistake, and so is having an explicit non-trivial Clone implementation without an explicit a destructor. The reason being is that implementing either of those implies that the type is managing resources, and the default implementation is going to be wrong here. Alternatively either of those is implemented for recursive data types (linked lists, trees, JSON objects) to prevent stack overflow while forgetting about the other one.

Note that having a Drop implementation while not implementing Clone at all is fine.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the issue description and investigate how Clippy represents existing lints for Drop and Clone. Define how trivial Clone implementations and ZST fields should be treated before choosing the lint scope; done means the behavior is specified and the proposed lint consistently flags the described mismatches without flagging the stated exceptions.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.