Currently it is possible and useful to use ManuallyDrop
, MaybeUninit
or std::ptr::drop_in_place
for writing generic datatypes Foo<T>
that implement Drop
in a way that actually does nothing if std::mem::needs_drop<T>() == false
. I can imagine things like owned pointers to the stack or an arena, or using ManuallyDrop
just to specify drop order. And there’s probably lots of scenarios I’m not thinking of, basically everything where the destructor must be written manually but does not handle any synchronization logic or deallocation. I guess, this can also include Box<T>
for zero-sized drop-glue-free T
.
Right now, for such a type Foo<T>
we have std::mem::needs_drop::<Foo<T>>
evaluating to true
. This in turn means that something like Vec<Foo<T>>
will loop through the whole vector with a no-op destructor (unless the optimizer catches this, which seems likely; but there ought to be some better examples, otherwise needs_drop()
wouldn’t exist, right?)
As far as I’m aware, needs_drop
is allowed to change its implementation without this being considered a breaking change, which means that the current behavior can be changed, and also my proposed new behavior below is not a semver hazard (as it will introspect the actual Drop
implementation source code which breaks encapsulation a bit).
So my idea is that we could have the Rust compiler realize certain kinds of no-op Drop
implementations are doing nothing and use this to improve the information provided by std::mem::needs_drop
.
Possible cases for improvement:
- Definitely possible and quite minimal approach: If a type where none of the fields have drop glue implements
Drop
in a way that the whole body offn drop
is wrapped in aif COND { ... }
whereCOND
is an expression that can beconst
-evaluated (or how do you call that? I mean something that could be assigned toconst
s orstatic
s), thenstd::mem::needs_drop()
should returnfalse
whenever thisCOND
evaluates tofalse
; and in this case the type itself would also be considered not to have drop glue. This would give people that want their types to not have drop glue a quite powerful way to archive it. - Maximal approach: Whenever a destructor (including its drop glue) is compiled to a no-op after optimization, then the corresponding
needs_drop()
check returnsfalse
for that type. Possibly difficult / impossible since this would make aconst fn
depend on the result of the optimizer, which probably includes LLVM (however I have no idea how the rust compiler actually works, so who knows). This approach would however give the greatest performance benefit to unmaintained or non-handoptimized code. - Middle ground: Allow a few more things next to the
if COND
guarded stuff, likeMaybeUninit::assume_init
orstd::ptr::drop_in_place
orManuallyDrop::drop
, etc, to make some very simpleDrop
implementations work without need for change. It is however highly nontrivial to decide what to include in such an analysis.
I’m interested in whether you think this is reasonable idea and a valuable improvement, and if yes, which version/kind of analysis you think is possible and useful. Also links to previous discussion about anything related would be appreciated. With positive feedback, we could try to make an RFC out of this.