Does a type that implements copy get moved if possible?

Viewed 183

If you pass a type into a function that is not a pointer type and it implements Copy, does Rust copy it only if necessary?

Here is some specific code:

#[derive(Clone, Copy)]
struct Data([u8; 2]);

#[derive(Clone, Copy)]
struct Buffer(Data);

fn do_something(id: Buffer) {
    println!("{}", id.0.0[0]);
}

fn create_buffer() -> Buffer {
   Buffer(Data([0x01, 0x01]))
}

fn main() {
    let buffer = create_buffer();

    // Since we don't use buffer again in this function, copy trait isn't necessary on Buffer.
    // But, "Buffer" does implement the Copy trait. Will Rust copy it anyway?
    do_something(buffer);
}

If rust does not copy it, are there rules to this behavior or is it entirely up to the compiler to decide? Can I rely on this not being copied?

What if I were to call do_something(buffer) twice? Does it copy twice, or move once and copy once? This requires the copy trait to even compile so I expect at least 1 copy.

do_something(buffer);
do_something(buffer);
1 Answers

move and copy are solely type system concerns denoting whether the source can or can not still be used (by high-level code) after it has been used once[0]. In the lingo, it only defines whether the type is affine (aka move, the default) or normal (Copy)

After typechecking, both result in the same actual operation: a memcopy (semantically), then the normal elision optimisations will work the same for both and may optimise away the actual copy.

So the answer would be "yes". At a codegen level, there really is no difference between Copy and non-Copy types as long as they are used in the same way. Do note that the elision optimisation may fail to trigger in both cases. In fact there are issues on the tracker (some closed and some not) where "move elision" fails to trigger, and a large on-stack non-Copy type gets copied around.

[0] I believe there is limited NRVO and plans for more in MIR / rustc itself, but the vast majority of the work is left to LLVM: https://github.com/rust-lang/rust/issues/32966

Related