← Back to #1521
PR #3197Work-in-progress preview from an open pull request.View on GitHub ↗
REVIEW
#1521

copy-clone-semantics

Authoreggyal
CreatedNov 19 2021
UpdatedFeb 16 2022
Rust Issue

Clarify semantics of Clone so that users are permitted to assume that <T as Clone>::clone() where T: Copy is implemented by memcpy.

It's generally been an unspoken rule of Rust that a clone of a Copy type is equivalent to a memcpy of that type; however, that fact is not documented anywhere. This fact should be in the documentation for the Clone trait, just like the fact that T: Eq should implement a == b == c == a rules.

Motivation

Currently, Vec::clone() is implemented by creating a new Vec, and then cloning all of the elements from one into the other. This is slow in debug mode, and may not always be optimized (although it often will be). Specialization would allow us to simply memcpy the values from the old Vec to the new Vec in the case of T: Copy. However, if we don't specify this, we will not be able to, and we will be stuck looping over every value.

It's always been the intention that Clone::clone == ptr::read for T: Copy; see issue #23790: "It really makes sense for Clone to be a supertrait of Copy -- Copy is a refinement of Clone where memcpy suffices, basically." This idea was also implicit in accepting rfc #0839 where "[B]ecause Copy: Clone, it would be backwards compatible to upgrade to Clone in the future if demand is high enough."

Detailed design

Specify that users may assume <T as Clone>::clone(t) to be equivalent to ptr::read(t) where T: Copy, t: &T. An implementation that does not uphold this shall not result in undefined behavior; Clone is not an unsafe trait.

Also add something like the following paragraph to the documentation for the Clone trait:

"If T: Copy, x: T, and y: &T, then let x = y.clone(); is equivalent to let x = *y;. Implementors should be careful to uphold this invariant, as consumers may assume that it holds (though unsafe code must not rely on it holding as a precondition for memory safety). Note that the compiler itself will not assume that the invariant holds when compiling calls to Clone::clone, thereby guaranteeing that the relevant clone method will be invoked."

Drawbacks

This is a breaking change, technically, although it breaks code that was malformed in the first place.

Alternatives

The alternative is that, for each type and function we would like to specialize in this way, we document this separately. This is how we started off with clone_from_slice.

Unresolved questions

What the exact wording should be.