Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

librustc: Make Copy opt-in. #17864

Closed
wants to merge 1 commit into from
Closed

Conversation

pcwalton
Copy link
Contributor

@pcwalton pcwalton commented Oct 8, 2014

This change makes the compiler no longer infer whether types (structures
and enumerations) implement the Copy trait (and thus are implicitly
copyable). Rather, you must implement Copy yourself via impl Copy for MyType {}.

This breaks code like:

#[deriving(Show)]
struct Point2D {
    x: int,
    y: int,
}

fn main() {
    let mypoint = Point2D {
        x: 1,
        y: 1,
    };
    let otherpoint = mypoint;
    println!("{}{}", mypoint, otherpoint);
}

Change this code to:

#[deriving(Show)]
struct Point2D {
    x: int,
    y: int,
}

impl Copy for Point2D {}

fn main() {
    let mypoint = Point2D {
        x: 1,
        y: 1,
    };
    let otherpoint = mypoint;
    println!("{}{}", mypoint, otherpoint);
}

This is the backwards-incompatible part of #13231.

Part of RFC #3.

[breaking-change]

r? @nikomatsakis

@rust-highfive
Copy link
Collaborator

warning Warning warning

  • These commits modify unsafe code. Please review it carefully!

@sfackler
Copy link
Member

sfackler commented Oct 8, 2014

It'd be nice to allow #[deriving(Copy)].

@killercup
Copy link
Member

Link to the RFC

@nikomatsakis
Copy link
Contributor

Exciting! Can't wait to review.

One nit. You write:

This is the backwards-incompatible part of #13231.

But in fact there is another backwards incompatible part, concerning whether *T is send or not.

@Manishearth
Copy link
Member

#[deriving(Copy)] should be easy enough, we just need to copy the code for Eq with an empty combine_substructure or something similar.

@thestinger
Copy link
Contributor

If you implement Clone, your type is cloneable, meaning that it moves from place to place, but it can be explicitly cloned. This is suitable for cases where copying is expensive.

If you implement Copy, your type is copyable, meaning that it is just copied by default without the need for an explicit clone. This is suitable for small bits of data like ints or points.

As long as the Copy guarantees are being leveraged by types like Cell, the RFC is incorrect. It's incorrect to leave out a Copy implementation based on how expensive it would be. The lack of an automatic Clone implementation for all Copy types is a significant language wart. The system in C++ is not as transparent about costs but at least it's coherent.

@bstrie
Copy link
Contributor

bstrie commented Oct 9, 2014

@thestinger, is it mentioned anywhere that we don't want Copy to imply Clone? I know it's not possible today, but I was under the impression that trait reform would make such blanket impls feasible.

@thestinger
Copy link
Contributor

#17884

@nikomatsakis nikomatsakis mentioned this pull request Oct 10, 2014
7 tasks
@flaper87
Copy link
Contributor

cc @flaper87

@@ -476,6 +481,114 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
}
}
}

/// Ensures that implementations of the built-in trait `Copy` are legal.
fn check_implementations_of_copy(&self) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this method be made more generic in order to cover also other built-in traits?

In my last PR I had a visitor that would run the checks below for each implementation of a built-in trait.

I like the implementation of this PR better but there's probably something we can rescue from the old one since for other built-in traits we'll need the same checks on fields and variants.

@pcwalton
Copy link
Contributor Author

r? @nikomatsakis

@nikomatsakis
Copy link
Contributor

r+ modulo bare fns and the nit about just calling through to assemble_builtin_candidates unconditionally

@mitsuhiko
Copy link
Contributor

Has there been a discussion about keeping the old Copy trait stick around under a new name for code like Cell can make assumptions about it? The compiler could do what it did for Copy in the past but for a new trait called Pod for instance which has no user facing API implications.

@thestinger
Copy link
Contributor

Every case where a type had Copy before but not after the commits is a regression unless there's a soundness issue with having it. The timeval and timespec types in liblibc should remain Copy, among others. If going through all the types and making decisions is too large of a maintenance burden then there's a problem with this design decision. It's going to break a huge amount of third party code and there is no possible migration path in cases where at least one field is private.

@sfackler
Copy link
Member

@mitsuhiko I'm not sure I understand how Pod would be distinct from current Copy. Could types under a Pod bound be copied? How would it have no user facing API implications if it were usable by users?

@thestinger
Copy link
Contributor

I think there needs to be a lint to determine when a type is able to implement Copy, and all of the warnings should be fixed. It can be allowed on the few (5-10?) types that are supposed to lack a Copy implementation but are able to provide it. This would catch all of the regressions.

@mitsuhiko
Copy link
Contributor

@sfackler Copy had two meanings: copies implicitly and can be copied with memcpy. Even under the new system it makes absolutely no sense that Copy could be implemented for non pod types. As such it makes sense to have an automatic Pod type and to use that to aid the developer (warn if copy is missing, error if copy cannot be a memcpy). Likewise for data structures like Cell currently relying on Copy it makes sense to switch over to Pod and to also support the types that can no longer be copied implicitly.

@mitsuhiko
Copy link
Contributor

(To add to that: figuring out if something is a Pod type or not is something that is very useful. C++ for instance comes with an std::is_pod template)

@nikomatsakis
Copy link
Contributor

@mitsuhiko the semantics of Copy are not changed by this patch. The only change is that it becomes opt-in.

@mitsuhiko
Copy link
Contributor

@mitsuhiko the semantics of Copy are not changed by this patch. The only change is that it becomes opt-in.

I understand that, but why not have an always implemented Pod trait that is a superset of it? There are situations in which you might want the guarantee of it being safe for memcpy but still have the implicit copy disabled.

@pcwalton
Copy link
Contributor Author

pcwalton commented Nov 4, 2014

@thestinger "It's too hard to change right now" was explicitly not considered a valid reason to not make this change.

@pcwalton
Copy link
Contributor Author

pcwalton commented Nov 4, 2014

That said I'm adding the lint right now, for public types without any type parameters.

@pcwalton pcwalton force-pushed the oibit2 branch 2 times, most recently from 051aa46 to a9fd710 Compare November 11, 2014 06:57
@pcwalton
Copy link
Contributor Author

r? @nikomatsakis (lint added per @thestinger's suggestion)

@nikomatsakis
Copy link
Contributor

r+ here are comments (from IRC):

[08:12:49] <nmatsakis> pcwalton: do we want to impose a rule that you cannot impl Copy if you impl Drop? (and do you impose such a rule?)
[08:12:56] <nmatsakis> pcwalton: it's not obvious to me that this restriction is NECESSARY
[08:13:16] <nmatsakis> pcwalton: though perhaps at minimum we shouldn't lint about it I guess
[08:13:24] <nmatsakis> pcwalton: but basically r+
[08:14:02] <nmatsakis> pcwalton: I read the changes to middle::traits and middle:coherence, I assume the rest is fallout. <nag>it'd be helpful to segregate that into its own commit.</nag>
[08:14:04] <nmatsakis> I'll leave a comment

@tamird
Copy link
Contributor

tamird commented Dec 1, 2014

looks like this needs a rebase

@nikomatsakis
Copy link
Contributor

@pcwalton r+ but needs rebase

This change makes the compiler no longer infer whether types (structures
and enumerations) implement the `Copy` trait (and thus are implicitly
copyable). Rather, you must implement `Copy` yourself via `impl Copy for
MyType {}`.

A new warning has been added, `missing_copy_implementations`, to warn
you if a non-generic public type has been added that could have
implemented `Copy` but didn't.

This breaks code like:

    #[deriving(Show)]
    struct Point2D {
        x: int,
        y: int,
    }

    fn main() {
        let mypoint = Point2D {
            x: 1,
            y: 1,
        };
        let otherpoint = mypoint;
        println!("{}{}", mypoint, otherpoint);
    }

Change this code to:

    #[deriving(Show)]
    struct Point2D {
        x: int,
        y: int,
    }

    impl Copy for Point2D {}

    fn main() {
        let mypoint = Point2D {
            x: 1,
            y: 1,
        };
        let otherpoint = mypoint;
        println!("{}{}", mypoint, otherpoint);
    }

This is the backwards-incompatible part of rust-lang#13231.

Part of RFC rust-lang#3.

[breaking-change]
@alexcrichton
Copy link
Member

Closing in favor of #19566

lnicola pushed a commit to lnicola/rust that referenced this pull request Aug 13, 2024
fix: Build and run build scripts in lsif command
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.