-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
The tail_expr_drop_order
lint today gives a lot of false positives
#130836
Comments
@rustbot labels +T-lang +I-lang-nominated +C-discussion |
Report from crater run #129604From this crater run, we found these inprecise diagnoses. We should not lint against upvarsIn this example the We should not lint against values moved into return place or consumedIn this example, droppy values are moved into the return value. Their destructor would not even be called. There exists types that we don't careIt turns out types like |
I also devised a "recursive lock" (???) example to demonstrate the significance of drop order as the first try. use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::{Acquire, Release};
static SEMAPHORE: AtomicUsize = AtomicUsize::new(0);
struct S(usize);
impl S {
fn new() -> Self {
Self(SEMAPHORE.fetch_add(1, Acquire))
}
fn get(&self) -> usize {
self.0
}
}
impl Drop for S {
fn drop(&mut self) {
assert_eq!(self.0 + 1, SEMAPHORE.fetch_sub(1, Release));
}
}
fn semaphore_test() -> usize {
let s1 = S::new();
let s2 = S::new();
S::new().get()
}
fn main() {
let x = semaphore_test();
println!("{x}")
} |
@rustbot labels -I-lang-nominated We talked about this last week, resulting in further discussions that resulted in an implementation with fewer false positives. Please of course renominate if there are any further questions there. |
…t-2, r=<try> Reduce false positives of tail-expr-drop-order from consumed values (attempt #2) r? `@nikomatsakis` Related to rust-lang#129864 but not replacing, yet. Related to rust-lang#130836. This is an implementation of the approach suggested in the [Zulip stream](https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/temporary.20drop.20order.20changes). A new MIR statement `BackwardsIncompatibleDrop` is added to the MIR syntax. The lint now works by inspecting possibly live move paths before at the `BackwardsIncompatibleDrop` location and the actual drop under the current edition, which should be one before Edition 2024 in practice.
…t-2, r=<try> Reduce false positives of tail-expr-drop-order from consumed values (attempt #2) r? `@nikomatsakis` Related to rust-lang#129864 but not replacing, yet. Related to rust-lang#130836. This is an implementation of the approach suggested in the [Zulip stream](https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/temporary.20drop.20order.20changes). A new MIR statement `BackwardsIncompatibleDrop` is added to the MIR syntax. The lint now works by inspecting possibly live move paths before at the `BackwardsIncompatibleDrop` location and the actual drop under the current edition, which should be one before Edition 2024 in practice.
…t-2, r=<try> Reduce false positives of tail-expr-drop-order from consumed values (attempt #2) r? `@nikomatsakis` Tracked by rust-lang#123739. Related to rust-lang#129864 but not replacing, yet. Related to rust-lang#130836. This is an implementation of the approach suggested in the [Zulip stream](https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/temporary.20drop.20order.20changes). A new MIR statement `BackwardsIncompatibleDrop` is added to the MIR syntax. The lint now works by inspecting possibly live move paths before at the `BackwardsIncompatibleDrop` location and the actual drop under the current edition, which should be one before Edition 2024 in practice.
…t-2, r=<try> Reduce false positives of tail-expr-drop-order from consumed values (attempt #2) r? `@nikomatsakis` Tracked by rust-lang#123739. Related to rust-lang#129864 but not replacing, yet. Related to rust-lang#130836. This is an implementation of the approach suggested in the [Zulip stream](https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/temporary.20drop.20order.20changes). A new MIR statement `BackwardsIncompatibleDrop` is added to the MIR syntax. The lint now works by inspecting possibly live move paths before at the `BackwardsIncompatibleDrop` location and the actual drop under the current edition, which should be one before Edition 2024 in practice.
…t-2, r=nikomatsakis Reduce false positives of tail-expr-drop-order from consumed values (attempt #2) r? `@nikomatsakis` Tracked by rust-lang#123739. Related to rust-lang#129864 but not replacing, yet. Related to rust-lang#130836. This is an implementation of the approach suggested in the [Zulip stream](https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/temporary.20drop.20order.20changes). A new MIR statement `BackwardsIncompatibleDrop` is added to the MIR syntax. The lint now works by inspecting possibly live move paths before at the `BackwardsIncompatibleDrop` location and the actual drop under the current edition, which should be one before Edition 2024 in practice.
cc @traviscross
TL;DR
We have implemented a HIR-based lint against changes in drop order due to
#![feature(shorter_tail_lifetimes)]
.Through a crater run we learnt that this approach produces a lot of false positives. We need to account for control flow and track the use of places and partial moves. How can we achieve this?
Current status
The current approach to identify temporaries in tail expression whose drop order may change is to identify local variable declarations as well as (sub)expressions of the tail expression that are of types with significant drop implementation. The lint will then simply assume that all of them will observe a change in drop order and report as such.
For example, the following code is linted against.
MIR shows that the temporary value
_6
is indeed dropped later that_1
aka.x
.MIR
Drawbacks
This lint is now too naive. For instance, the following example clearly will not have the drop order changed. The analysis does not consider the fact that temporary values can be moved and the drop on the locals or places are effectively no-ops.
This is a fairly common case. From the last crater run we learnt it from the fact that
serde::Deserialize
macro keeps the partially deserialized data as locals and later moves them into the return value. The lint was triggered even though those values are not dropped at the function return point.New attempts
Therefore, we need to improve the lint so that the analysis is more precise by factoring in the control flow and the kind of use of various MIR places, especially partial moves. Solving this issue perfectly requires one to inspect MIR instead, in conjunction with
MaybeUninitializedPlaces
data flow. Identifying which statements in MIR is today accurate enough, but we can't say the same fordrop
terminators. In the earliest attempts of #129864, span information in the terminators turned out to be pointing outside the tail expression span even though they properly fulfill the drop schedules for the tail expression. This gave us even more false positives and negatives.As an example, we saw that the drop happened at the last closing bracket of this code from the MIR
source_info
on the drop terminators.One possible way to address this incorrect information is to extend MIR syntax so that
drop
terminators carry information on which exactly the HIR region scope the drops are scheduled for. With it we can precisely differentiate drops for the proper tail expression, the drops for the locals in the body and, in particular, Edition 2021 temporary values that dropped not as part of the tail expression drop schedule. Those are the targets this lint is exactly looking for.Drawbacks
Due to copying and retention of this scope information in MIRs, there is now regression on compiler performance.
Questions
The text was updated successfully, but these errors were encountered: