Change:
currently doesn't need drop glue by itself but still adds liveness requirements for when used in a more complex value which already needs drop. This behavior is identitical to , which also does not need drop glue by itself but adds liveness requirements when used in values who do. I do not propose to change anything about with this issue. This behavior is confusing. I propose that we don't add any dropck outlives requirements for arrays of length zero. This allows strictly more code to compile, it may however result in unsoundness if people rely on this behavior to guarantee errors.
cc for more details about dropck fcp merge
Team member has proposed to merge this. The next step is review by the rest of the tagged team members: [x] [x] [x] [x] [ ] [x] [ ] Concerns: resolved by resolved by Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See for info about what commands tagged team members can give me.
How (if at all) does this interact with const generics? What if the length is unknown but could be zero? Seems surprising that behavior depends so heavily on whether the compiler can "figure out" the length.
This happens after type inference, so we should only fail to evaluate for generic constants. In this case they are always considered to be potentially non-zero. yes, I considered to propose changing the behavior for arrays to always require drop glue, even for because relying on the value of constants in this way is always a bit sketchy. The problem is that this is actually quite useful. I am a bit confused by why exactly this errors, but the following snippet would fail if we remove the special case for zero length arrays in opened if you want to take a deeper look at this. Afaict we never actually drop here so this is the const check being too pessimistic (iirc using dataflow for that was too involved so we didn't end up stabilizing precise const drop). concern we could instead stop specialcasing in
What probably happens is that cannot get promoted any more because it looks like that would skip some drop glue. Presumably this also fails with your patch, saying the value does not live long enough?
no, this still works :sweat_smile: apparently promotion does work. Had the same idea at first when seeing the test failures
Hm, maybe promotion has its own knowledge that never needs to run any drop glue...
Promotion for arrays (unlike any other type) even supports mutable references, i.e. , so I wouldn’t be surprised if hits some special case as well.
resolve we could instead stop specialcasing in doing so results in too many regressions, see
I'm not convinced yet that we want to ditch that option. Clearly there's something going on that we don't understand -- if this still works then this should also still work This looks like an issue specific to promotion, not something related to dropck in general.
Note that this also works so "promotion of types that need dropping, if we know that the value doesn't need dropping", is already a thing. would also fit that category. This works even with , so it seems worth figuring out why it stops working for arrays in .
If a local is defined by an assignment from Rvalue::Aggregate, its value needs to be dropped if a type inherently needs drop, i.e., it implements Drop, or if any operands needs to be dropped (that in turns depends how those locals or constants are defined). For example: Additionally, in const checking (but not in promotion which works differently here), if a place with a type that needs drop is borrowed, and borrows allows for mutation (mutable borrow or borrowed place is not Freeze), then the value of local needs dropping. For example: Note that is not Freeze, and without the special case it needs drop.
concern rushed-fcp I personally don't feel comfortable making non-gated changes here right now. As I noted on zulip, I'm not really satisfied with the answer regarding const generics. And, it seems like there is still deeper discussion to be had (glancing at the above comments). I would feel more comfortable canceling FCP here in favor of more discussion and gated experimentation. Ultimately, I might be swayed with a very detailed and well thought out writeup of the problems here and intended solution, though.
rushed-fcp seems fair, how about rust-lang/rfcs ?
hmm, I originally assumed to this be fairly straightforward. Will attempt to provide a full summary of the issue and the proposed solution: Implicitly dropping variables during borrowck is different from explicitly calling in that the variables don't have to be fully live. Dropping a variable uses drop glue. Conceptionally drop glue recursively calls for all owned values. For drop glue to be sound all regions used in a - potentially builtin - impl have to be live. Computing this is currently done in two steps: Check whether there is any drop glue via , i.e. may variables of this type own a value which has a impl. If so, compute the regions which have to be live for these impls using . For these two methods disagree: returns while assumes that we may drop a in the drop glue of (which does not exist). This means that whether implicitly dropping requires to be droppable relies on whether another type owned by this variable requires drop glue. See for how this impacts stable code. I consider this current behavior to clearly be a bug and something we have to fix[^1]. I believe there to only be two valid options This is the alternative proposed by The idea is to change to remove the specialcase for zero length arrays. We would add (noop) drop glue for if has drop glue. This removes our reliance on const generics/const evaluation in drop computation. I have implemented that approach in . This is what I proposed for FCP. We add a check for zero lenth arrays in . This would mean that we now consistently consider to not have any drop glue. I strongly believe that we should keep the specialcase for and also add it in . Afaict the main concern is that specialcasing relies on const generics. Checking implicit drops only happens after type inference. This means array lengths are in one of the following states: : could be anything seems trivially correct to require to be droppable. (evaluable to) : can trivially check for . a generic constant (with ): If the constant is actually still generic and relies on a generic parameter, it also feels fairly straightforward to require to be droppable. The actual interaction with const generics is therefore really limited and straightforward imo. I stated the following in : The reason I consider this to be slightly sketchy is that it is hard to emulate by purely using the trait system, especially on stable. I don't know how (and why) we would ever move dropck fully into the trait system so I am not very worried here. I think that the specialcase is both actually desirably and necessary for backwards compatability. If acts if it may drop , one cannot use references to in const contexts. This breaks using generic empty slices: See by for why this breaks. I expect it to be difficult to resolve this issue without adding another specialcase depending on the array length for that. I may be wrong and there's a sensible way to change const checking. should have a better understanding of the design space here. Crater found a few root regressions with a total of a few hundred affected projects. Even if we fix this specific somewhat weird regression this would still be a breaking change. We would for example break  which actually drops an array of length zero. I dislike the idea of breaking existing code without a strong reason. Ignoring the status quo, I still think we should specialcase . It allows strictly more code to soundly compile and I believe it fits the way users - and I - think about Rust. I don't expect anyone to be confused by not requiring to be live and can imagine bug reports if they encounter a case where we do. Even if we do end up moving dropck into the trait system the specialcase for zero does not cause any new issue as we have a similar issue with and in for . I think that going forward we already want to add a way to enable this pattern using stable trait system features. I hope this writeup is useful. The only place that's still unclear to me is whether the current const checking behavior is too strict and we can change this pattern to compile: That won't change my perspective on this FCP though. I don't believe that looking further into this is worth it, unless you first disagree with the rest of my arguments. [^1]: The same issue exists for which I am trying to fix separately via as that is more involved.
if we do opt to apply to , a simple fix for crates that use it for alignment (since, unlike , follows the alignment of ) would be to use with it. tho not sure if that works with .
oh I see... with interior mutability the value might change before it is dropped so the value-based analysis gives up. That makes sense. thanks for the writeup! Yes that is probably correct, so this pretty much defeats my argument. This is fair. My remaining concern here is consistency: the reasoning above applies not just to dropping. To name an example, is not even though it could be. So while "array length 0 does not give any special powers" might be surprising at first, at least it is easy to teach and explain and internalize. The alternative is a world where some analyses know about empty arrays being special and others do not. This can be more startling than applying the same principle consistently. Of course we could set a goal to make 0 special for more cases (Copy, Clone, Default, ...); then the question is -- how realistic is it to achieve that goal? Well, it would force us to add such a special case to the trait system before we can do the move. Currently we don't have such a special case, right? And it is unclear whether specialization will be powerful enough for this.
We already have that special case for , blocking us from replacing the 33 impls with const generics ;+0%5D The specialcase also exists in the wild, e.g. in serde: ;+0%5D Using some compiler hack and marker traits it is already possible right now, allowing this behavior on stable is probably also a longterm goal.
Ah, fair, I didn't know that.
will discuss this as part of
resolve rushed-fcp While I'm not ready to check my box yet, this was obviously discussed, so resolving concern
:bell: This is now entering its final comment period, as per the . :bell:
The final comment period, with a disposition to merge, as per the , is now complete. As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed. This will be merged soon.
implemented in , we still need to update the documentation however, cc
love when rust breaks crate soundness, top-tier language

Discussion:
/// still be live when `T` gets dropped. The exact details of this analysis are not yet /// stably guaranteed and **subject to change**. Currently, the analysis works as follows: /// - If `T` has no drop glue, then trivially nothing is required to be live. This is the case if <del> ///   neither `T` nor any of its (recursive) fields have a destructor (`impl Drop`). [`PhantomData`] ///   and [`ManuallyDrop`] are considered to never have a destructor, no matter their field type. </del> <ins> ///   neither `T` nor any of its (recursive) fields have a destructor (`impl Drop`). [`PhantomData`], ///   arrays of length 0 and [`ManuallyDrop`] are considered to never have a destructor, no matter ///   their field type. </ins> /// - If `T` has drop glue, then, for all types `U` that are *owned* by any field of `T`, ///   recursively add the types and lifetimes that need to be live when `U` gets dropped. The set of ///   owned types is determined by recursively traversing `T`: <del> ///   - Recursively descend through `PhantomData`, `Box`, tuples, and arrays (including arrays of </del> <ins> ///   - Recursively descend through `PhantomData`, `Box`, tuples, and arrays (excluding arrays of </ins> ///     length 0). ///   - Stop at reference and raw pointer types as well as function pointers and function items; ///     they do not own anything.