Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 68feb6c

Browse files
committed
add a test with incorrect if let-super let drop order
1 parent 1553adf commit 68feb6c

File tree

1 file changed

+112
-0
lines changed

1 file changed

+112
-0
lines changed

‎tests/ui/drop/if-let-super-let.rs

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
//! Test for #145328: ensure the lifetime of a `super let` binding within an `if let` scrutinee is
2+
//! at most the scope of the `if` condition. In particular, test `pin!` since it's implemented in
3+
//! terms of `super let`.
4+
//@ run-pass
5+
//@ revisions: e2021 e2024
6+
//@ [e2021] edition: 2021
7+
//@ [e2024] edition: 2024
8+
9+
#![feature(if_let_guard)]
10+
#![feature(super_let)]
11+
#![expect(irrefutable_let_patterns)]
12+
13+
use std::cell::RefCell;
14+
use std::pin::pin;
15+
16+
fn main() {
17+
// The `super let` bindings here should have the same scope as `if let` temporaries.
18+
// In Rust 2021, this means it lives past the end of the `if` expression.
19+
// In Rust 2024, this means it lives to the end of the `if`'s success block.
20+
assert_drop_order(0..=2, |o| {
21+
#[cfg(e2021)]
22+
(
23+
if let _ = { super let _x = o.log(2); } { o.push(0) },
24+
o.push(1),
25+
);
26+
#[cfg(e2024)]
27+
(
28+
if let _ = { super let _x = o.log(2); } { o.push(0) },
29+
o.push(1),
30+
);
31+
});
32+
assert_drop_order(0..=2, |o| {
33+
#[cfg(e2021)]
34+
(
35+
if let true = { super let _x = o.log(2); false } {} else { o.push(0) },
36+
o.push(1),
37+
);
38+
#[cfg(e2024)]
39+
(
40+
if let true = { super let _x = o.log(2); false } {} else { o.push(0) },
41+
o.push(1),
42+
);
43+
});
44+
45+
// `pin!` should behave likewise.
46+
assert_drop_order(0..=2, |o| {
47+
#[cfg(e2021)] (if let _ = pin!(o.log(2)) { o.push(0) }, o.push(1));
48+
#[cfg(e2024)] (if let _ = pin!(o.log(2)) { o.push(0) }, o.push(1));
49+
});
50+
assert_drop_order(0..=2, |o| {
51+
#[cfg(e2021)]
52+
(
53+
if let None = Some(pin!(o.log(2))) {} else { o.push(0) },
54+
o.push(1),
55+
);
56+
#[cfg(e2024)]
57+
(
58+
if let None = Some(pin!(o.log(2))) {} else { o.push(0) },
59+
o.push(1),
60+
);
61+
});
62+
63+
// `super let` bindings' scope should also be consistent with `if let` temporaries in guards.
64+
// Here, that means the `super let` binding in the second guard condition operand should be
65+
// dropped before the first operand's temporary. This is consistent across Editions.
66+
assert_drop_order(0..=1, |o| {
67+
match () {
68+
_ if let _ = o.log(0)
69+
&& let _ = { super let _x = o.log(1); } => {}
70+
_ => unreachable!(),
71+
}
72+
});
73+
assert_drop_order(0..=1, |o| {
74+
match () {
75+
_ if let _ = o.log(0)
76+
&& let _ = pin!(o.log(1)) => {}
77+
_ => unreachable!(),
78+
}
79+
});
80+
}
81+
82+
// # Test scaffolding...
83+
84+
struct DropOrder(RefCell<Vec<u64>>);
85+
struct LogDrop<'o>(&'o DropOrder, u64);
86+
87+
impl DropOrder {
88+
fn log(&self, n: u64) -> LogDrop<'_> {
89+
LogDrop(self, n)
90+
}
91+
fn push(&self, n: u64) {
92+
self.0.borrow_mut().push(n);
93+
}
94+
}
95+
96+
impl<'o> Drop for LogDrop<'o> {
97+
fn drop(&mut self) {
98+
self.0.push(self.1);
99+
}
100+
}
101+
102+
#[track_caller]
103+
fn assert_drop_order(
104+
ex: impl IntoIterator<Item = u64>,
105+
f: impl Fn(&DropOrder),
106+
) {
107+
let order = DropOrder(RefCell::new(Vec::new()));
108+
f(&order);
109+
let order = order.0.into_inner();
110+
let expected: Vec<u64> = ex.into_iter().collect();
111+
assert_eq!(order, expected);
112+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /