Why can't `Drop` be implemented for only a subset of a type?

Consider the following code:

struct Struct<T>(std::marker::PhantomData<T>);

impl<T> Drop for Struct<T> where T: Copy {
    fn drop(&mut self) {}

I know it's fairly nonsensical, but it's a simplified example that illustrates the issue. Trying to compile this results in:

   Compiling playground v0.0.1 (/playground)
error[E0367]: `Drop` impl requires `T: std::marker::Copy` but the struct it is implemented for does not
 --> src/lib.rs:3:37
3 | impl<T> Drop for Struct<T> where T: Copy {
  |                                     ^^^^
note: the implementor must specify the same requirement
 --> src/lib.rs:1:1
1 | struct Struct<T>(std::marker::PhantomData<T>);
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0367`.
error: could not compile `playground`.

To learn more, run the command again with --verbose.

Why doesn't Rust allow this?

Rust's specialization is still a work in progress, I think?

This isn't specialization. You can implement traits for a subset of a type. For example:

struct Struct<T>(std::marker::PhantomData<T>);

impl<T> Clone for Struct<T> where T: Copy {
    fn clone(&self) -> Self { Struct(std::marker::PhantomData) }

But for some reason Drop doesn't allow this.

Ah I see. I found a passing comment that refers to Drop being a very special trait. https://github.com/rust-lang/rust/issues/46893

Yes, it could be done. That said, in general Drop is already so special-cased in the type system this does sound like a recipe for bugs.

1 Like

Interesting. Thanks for linking to that.

Some searching led to dropck.rs, which is where this check is implemented. Looking at the blame, this was implemented due to issue #8142 ("Prohibit specialized drops"). It looks like this was implemented because pre-1.0 Rust incorrectly monomorphised drop glue (i.e. types that didn't match the where bounds would still get the Drop implementation applied to them). This was implemented as part of Rust 1.0.

Well, that answers the why part of the question. Now I'll head over to the internals forum to see if this can be relaxed (obviously this would require fixing Drop glue and monomorphization).


This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.