Negative Drop impls, Drop auto-trait and ImplicitDrop

What meaning we want from this:

impl !Drop for T {};
  • Forbid? Unfortunate.
  • ...

The Drop is implicitly implemented for all types in Rust. Why would it not be an implied trait?

Next, there is wanting of some linear type support in rust, which conflate with Drop and panics...

However, we can make an opposite feature: ImplicitDrop: Drop trait. It's also implied for all fitiing types, can be opted out via ?ImplicitDrop bound and a negative impl.
The types which do such an opt out can still be dropped, except this must happen explicitly (via drop or drop_in_place).

So at the end we have following situation:

Do a type implement Drop ?

  1. Yes (explicitly of by compiler's derive)
    Do a type implement ImplicitDrop ?
    • Yes (has not opted out)
      Behaves as today
    • No
      Cannot go out of scope - must be dropped manually. (but panic still calls drop implicitly) (New)
  2. No (has a negative impl)
    Cannot go out of scope, or be manually dropped => needs special care of the programmer. Is a linear type => must be used somehow. (New)

To reduce possibilities of misuse, we should say that any type which needs destruction should rely on Drop.

What do you think?

There’s previous discussion on the topic. One of the most recent probably

which includes links to more topics, too.


That’s not quite accurate. The trait Drop itself is always explicit when it’s implemented. But types without Drop implementations can have so-called “drop glue”, which can (somewhat) be tested with mem::needs_drop. The situation as it currently stands also means that T: Drop bounds in (generic) Rust code are always useless.

5 Likes

And I want it to stay so.

Isn't drop glue also a part of dropping a value? We can do smth.equivalent to this:

auto trait Drop {
    default fn drop(&mut self) {}; //first we call this
    fn drop_glue(self) {std::intrinstics::drop_glue::<Self>(self)}; //then this; compiler provided
}

Then any Drop impl will be in fact a specialization.

So now we can properly make Drop an implied auto trait.

At least as it stands currently, the mechanism behind “auto trait” does not support anything but marker traits without any methods.

It has a meaning on nightly (unratified by RFC as yet).

From the hackmd:

With the feature gate negative_impls , we now permit negative impls as well as positive ones:

impl<T: ?Sized> !DerefMut for &T { }

Negative impls indicate a semver guarantee that the given trait will not be implemented for the given types.

See also.

2 Likes

While this all is also true, my question is more concrete: what if a type will never be implementing Drop, how to dispose it then?

e.g do we want drop glue to be a part of Drop's contract? If yes, what to do with !Drop types.

If no, do we want it to stay in such a grey, unspecified area, where it is now?

It's not really all that complicated a situation currently.

When a value goes out of scope (or you call ptr::drop_in_place on it), its drop glue is run. Said drop glue does two things:

  • If the type of the value has an implementation of Drop, calls Drop::drop(&mut value)
  • Recursively runs the drop glue of each of the value's fields

(This can actually sometimes lead to a problematic amount of IR bloat sometimes, in that the fields' drop calls are separate inlining candidates rather than one sharable, outlinable group.)

As an optimization, if mem::needs_drop returns false, you know that drop glue is recursively guaranteed to be a noöp, and can skip running any drop glue.


It's important to note that a type doesn't have to implement Drop to be disposed of. In fact, any type which implements Copy implicitly has a guarantee to never implement Drop.

An important part of the impl !Trait proposal is that it's not removing anything. All it's doing is saying you'll never impl Trait. It would be correct to say that there's impl<T: Copy> !Drop for T {} in the standard library.

1 Like

Note that there are a bunch of rules that depend on types not being Drop. For example, you can't move out of a field of a type that implements Drop, but you can move out of a type which needs_drop because of a field but does not have its own Drop.

Thus a change like this would be a breaking change.

2 Likes

Personally, I would prefer a proposal that removes the need for negative reasoning about Drop entirely, such as the one discussed here:

Indeed. The solution is either to add more magic - "is there Drop specialization for type or not?" - or to go with trait approach. I think of something like Dropable auto trait for drop glue, which Drop requires. Opting out from this makes (values of) a type to require programmer attention.

What's the problem with it?

Some of it is explained in the linked thread, but roughly: I think positive-only reasoning better fits conceptually. It allows you to uniformly think of traits as capabilities that allow you to do certain things: right now Drop is the only trait that signals obligation. Avoiding negative reasoning makes it possible to soundly make a default assumption that a trait is not implemented for a type until proven otherwise.