Skip to content

Commit d58ccd4

Browse files
committed
Remove let_chains feature
1 parent ed2d759 commit d58ccd4

37 files changed

+1059
-1186
lines changed

compiler/rustc_ast_passes/src/feature_gate.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
469469
"`if let` guards are experimental",
470470
"you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`"
471471
);
472-
gate_all!(let_chains, "`let` expressions in this position are unstable");
473472
gate_all!(
474473
async_trait_bounds,
475474
"`async` trait bounds are unstable",

compiler/rustc_feature/src/unstable.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -552,8 +552,6 @@ declare_features! (
552552
(unstable, large_assignments, "1.52.0", Some(83518)),
553553
/// Allow to have type alias types for inter-crate use.
554554
(incomplete, lazy_type_alias, "1.72.0", Some(112792)),
555-
/// Allows `if/while p && let q = r && ...` chains.
556-
(unstable, let_chains, "1.37.0", Some(53667)),
557555
/// Allows using `#[link(kind = "link-arg", name = "...")]`
558556
/// to pass custom arguments to the linker.
559557
(unstable, link_arg_attribute, "1.76.0", Some(99427)),

compiler/rustc_parse/messages.ftl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ parse_async_move_order_incorrect = the order of `move` and `async` is incorrect
5252
5353
parse_async_use_block_in_2015 = `async use` blocks are only allowed in Rust 2018 or later
5454
55+
parse_let_chain_pre_2024 = let chains are only allowed in Rust 2024 or later
56+
5557
parse_async_use_order_incorrect = the order of `use` and `async` is incorrect
5658
.suggestion = try switching the order
5759

compiler/rustc_parse/src/errors.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1778,6 +1778,13 @@ pub(crate) struct AsyncBoundModifierIn2015 {
17781778
pub help: HelpUseLatestEdition,
17791779
}
17801780

1781+
#[derive(Diagnostic)]
1782+
#[diag(parse_let_chain_pre_2024)]
1783+
pub(crate) struct LetChainPre2024 {
1784+
#[primary_span]
1785+
pub span: Span,
1786+
}
1787+
17811788
#[derive(Diagnostic)]
17821789
#[diag(parse_self_argument_pointer)]
17831790
pub(crate) struct SelfArgumentPointer {

compiler/rustc_parse/src/parser/expr.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4117,7 +4117,9 @@ impl MutVisitor for CondChecker<'_> {
41174117
LetChainsPolicy::AlwaysAllowed => (),
41184118
LetChainsPolicy::EditionDependent { current_edition } => {
41194119
if !current_edition.at_least_rust_2024() || !span.at_least_rust_2024() {
4120-
self.parser.psess.gated_spans.gate(sym::let_chains, span);
4120+
self.parser.dcx().emit_err(errors::LetChainPre2024 {
4121+
span,
4122+
});
41214123
}
41224124
}
41234125
}

compiler/rustc_span/src/symbol.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1261,7 +1261,6 @@ symbols! {
12611261
le,
12621262
legacy_receiver,
12631263
len,
1264-
let_chains,
12651264
let_else,
12661265
lhs,
12671266
lib,

tests/coverage/branch/if-let.coverage

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
LL| |#![feature(coverage_attribute, let_chains)]
2-
LL| |//@ edition: 2021
1+
LL| |#![feature(coverage_attribute)]
2+
LL| |//@ edition: 2024
33
LL| |//@ compile-flags: -Zcoverage-options=branch
44
LL| |//@ llvm-cov-flags: --show-branches=count
55
LL| |

tests/coverage/branch/if-let.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
#![feature(coverage_attribute, let_chains)]
2-
//@ edition: 2021
1+
#![feature(coverage_attribute)]
2+
//@ edition: 2024
33
//@ compile-flags: -Zcoverage-options=branch
44
//@ llvm-cov-flags: --show-branches=count
55

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
// See drop-order-comparisons.rs
2+
3+
//@ edition: 2024
4+
//@ run-pass
5+
6+
#![feature(if_let_guard)]
7+
8+
fn t_if_let_chains_then() {
9+
let e = Events::new();
10+
_ = if e.ok(1).is_ok()
11+
&& let true = e.ok(9).is_ok()
12+
&& let Ok(_v) = e.ok(8)
13+
&& let Ok(_) = e.ok(7)
14+
&& let Ok(_) = e.ok(6).as_ref()
15+
&& e.ok(2).is_ok()
16+
&& let Ok(_v) = e.ok(5)
17+
&& let Ok(_) = e.ok(4).as_ref() {
18+
e.mark(3);
19+
};
20+
e.assert(9);
21+
}
22+
23+
fn t_guard_if_let_chains_then() {
24+
let e = Events::new();
25+
_ = match () {
26+
() if e.ok(1).is_ok()
27+
&& let true = e.ok(9).is_ok()
28+
&& let Ok(_v) = e.ok(8)
29+
&& let Ok(_) = e.ok(7)
30+
&& let Ok(_) = e.ok(6).as_ref()
31+
&& e.ok(2).is_ok()
32+
&& let Ok(_v) = e.ok(5)
33+
&& let Ok(_) = e.ok(4).as_ref() => {
34+
e.mark(3);
35+
}
36+
_ => {}
37+
};
38+
e.assert(9);
39+
}
40+
41+
fn t_if_let_chains_then_else() {
42+
let e = Events::new();
43+
_ = if e.ok(1).is_ok()
44+
&& let true = e.ok(8).is_ok()
45+
&& let Ok(_v) = e.ok(7)
46+
&& let Ok(_) = e.ok(6)
47+
&& let Ok(_) = e.ok(5).as_ref()
48+
&& e.ok(2).is_ok()
49+
&& let Ok(_v) = e.ok(4)
50+
&& let Ok(_) = e.err(3) {} else {
51+
e.mark(9);
52+
};
53+
e.assert(9);
54+
}
55+
56+
fn t_guard_if_let_chains_then_else() {
57+
let e = Events::new();
58+
_ = match () {
59+
() if e.ok(1).is_ok()
60+
&& let true = e.ok(8).is_ok()
61+
&& let Ok(_v) = e.ok(7)
62+
&& let Ok(_) = e.ok(6)
63+
&& let Ok(_) = e.ok(5).as_ref()
64+
&& e.ok(2).is_ok()
65+
&& let Ok(_v) = e.ok(4)
66+
&& let Ok(_) = e.err(3) => {}
67+
_ => {
68+
e.mark(9);
69+
}
70+
};
71+
e.assert(9);
72+
}
73+
74+
fn main() {
75+
t_if_let_chains_then();
76+
t_guard_if_let_chains_then();
77+
t_if_let_chains_then_else();
78+
t_guard_if_let_chains_then_else();
79+
}
80+
81+
// # Test scaffolding
82+
83+
use core::cell::RefCell;
84+
use std::collections::HashSet;
85+
86+
/// A buffer to track the order of events.
87+
///
88+
/// First, numbered events are logged into this buffer.
89+
///
90+
/// Then, `assert` is called to verify that the correct number of
91+
/// events were logged, and that they were logged in the expected
92+
/// order.
93+
struct Events(RefCell<Option<Vec<u64>>>);
94+
95+
impl Events {
96+
const fn new() -> Self {
97+
Self(RefCell::new(Some(Vec::new())))
98+
}
99+
#[track_caller]
100+
fn assert(&self, max: u64) {
101+
let buf = &self.0;
102+
let v1 = buf.borrow().as_ref().unwrap().clone();
103+
let mut v2 = buf.borrow().as_ref().unwrap().clone();
104+
*buf.borrow_mut() = None;
105+
v2.sort();
106+
let uniq_len = v2.iter().collect::<HashSet<_>>().len();
107+
// Check that the sequence is sorted.
108+
assert_eq!(v1, v2);
109+
// Check that there are no duplicates.
110+
assert_eq!(v2.len(), uniq_len);
111+
// Check that the length is the expected one.
112+
assert_eq!(max, uniq_len as u64);
113+
// Check that the last marker is the expected one.
114+
assert_eq!(v2.last().unwrap(), &max);
115+
}
116+
/// Return an `Ok` value that logs its drop.
117+
fn ok(&self, m: u64) -> Result<LogDrop<'_>, LogDrop<'_>> {
118+
Ok(LogDrop(self, m))
119+
}
120+
/// Return an `Err` value that logs its drop.
121+
fn err(&self, m: u64) -> Result<LogDrop<'_>, LogDrop<'_>> {
122+
Err(LogDrop(self, m))
123+
}
124+
/// Log an event.
125+
fn mark(&self, m: u64) {
126+
self.0.borrow_mut().as_mut().unwrap().push(m);
127+
}
128+
}
129+
130+
impl Drop for Events {
131+
fn drop(&mut self) {
132+
if self.0.borrow().is_some() {
133+
panic!("failed to call `Events::assert()`");
134+
}
135+
}
136+
}
137+
138+
/// A type that logs its drop events.
139+
struct LogDrop<'b>(&'b Events, u64);
140+
141+
impl<'b> Drop for LogDrop<'b> {
142+
fn drop(&mut self) {
143+
self.0.mark(self.1);
144+
}
145+
}

tests/ui/drop/drop-order-comparisons.e2021.fixed

Lines changed: 3 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// N.B. drop-order-comparisons-let-chains.rs is part of this test.
2+
// It is separate because let chains cannot be parsed before Rust 2024.
3+
//
14
// This tests various aspects of the drop order with a focus on:
25
//
36
// - The lifetime of temporaries with the `if let` construct (and with
@@ -25,7 +28,6 @@
2528
//@ run-pass
2629

2730
#![feature(if_let_guard)]
28-
#![cfg_attr(e2021, feature(let_chains))]
2931
#![cfg_attr(e2021, warn(rust_2024_compatibility))]
3032

3133
fn t_bindings() {
@@ -311,59 +313,6 @@ fn t_let_else_chained_then() {
311313
e.assert(9);
312314
}
313315

314-
#[cfg(e2021)]
315-
#[rustfmt::skip]
316-
fn t_if_let_chains_then() {
317-
let e = Events::new();
318-
_ = if e.ok(1).is_ok()
319-
&& let true = e.ok(9).is_ok()
320-
&& let Ok(_v) = e.ok(5)
321-
&& let Ok(_) = e.ok(8)
322-
&& let Ok(_) = e.ok(7).as_ref()
323-
&& e.ok(2).is_ok()
324-
&& let Ok(_v) = e.ok(4)
325-
&& let Ok(_) = e.ok(6).as_ref() {
326-
e.mark(3);
327-
};
328-
e.assert(9);
329-
}
330-
331-
#[cfg(e2024)]
332-
#[rustfmt::skip]
333-
fn t_if_let_chains_then() {
334-
let e = Events::new();
335-
_ = if e.ok(1).is_ok()
336-
&& let true = e.ok(9).is_ok()
337-
&& let Ok(_v) = e.ok(8)
338-
&& let Ok(_) = e.ok(7)
339-
&& let Ok(_) = e.ok(6).as_ref()
340-
&& e.ok(2).is_ok()
341-
&& let Ok(_v) = e.ok(5)
342-
&& let Ok(_) = e.ok(4).as_ref() {
343-
e.mark(3);
344-
};
345-
e.assert(9);
346-
}
347-
348-
#[rustfmt::skip]
349-
fn t_guard_if_let_chains_then() {
350-
let e = Events::new();
351-
_ = match () {
352-
() if e.ok(1).is_ok()
353-
&& let true = e.ok(9).is_ok()
354-
&& let Ok(_v) = e.ok(8)
355-
&& let Ok(_) = e.ok(7)
356-
&& let Ok(_) = e.ok(6).as_ref()
357-
&& e.ok(2).is_ok()
358-
&& let Ok(_v) = e.ok(5)
359-
&& let Ok(_) = e.ok(4).as_ref() => {
360-
e.mark(3);
361-
}
362-
_ => {}
363-
};
364-
e.assert(9);
365-
}
366-
367316
#[cfg(e2021)]
368317
#[rustfmt::skip]
369318
fn t_if_let_nested_else() {
@@ -470,59 +419,6 @@ fn t_let_else_chained_then_else() {
470419
e.assert(9);
471420
}
472421

473-
#[cfg(e2021)]
474-
#[rustfmt::skip]
475-
fn t_if_let_chains_then_else() {
476-
let e = Events::new();
477-
_ = if e.ok(1).is_ok()
478-
&& let true = e.ok(9).is_ok()
479-
&& let Ok(_v) = e.ok(4)
480-
&& let Ok(_) = e.ok(8)
481-
&& let Ok(_) = e.ok(7).as_ref()
482-
&& e.ok(2).is_ok()
483-
&& let Ok(_v) = e.ok(3)
484-
&& let Ok(_) = e.err(6) {} else {
485-
e.mark(5);
486-
};
487-
e.assert(9);
488-
}
489-
490-
#[cfg(e2024)]
491-
#[rustfmt::skip]
492-
fn t_if_let_chains_then_else() {
493-
let e = Events::new();
494-
_ = if e.ok(1).is_ok()
495-
&& let true = e.ok(8).is_ok()
496-
&& let Ok(_v) = e.ok(7)
497-
&& let Ok(_) = e.ok(6)
498-
&& let Ok(_) = e.ok(5).as_ref()
499-
&& e.ok(2).is_ok()
500-
&& let Ok(_v) = e.ok(4)
501-
&& let Ok(_) = e.err(3) {} else {
502-
e.mark(9);
503-
};
504-
e.assert(9);
505-
}
506-
507-
#[rustfmt::skip]
508-
fn t_guard_if_let_chains_then_else() {
509-
let e = Events::new();
510-
_ = match () {
511-
() if e.ok(1).is_ok()
512-
&& let true = e.ok(8).is_ok()
513-
&& let Ok(_v) = e.ok(7)
514-
&& let Ok(_) = e.ok(6)
515-
&& let Ok(_) = e.ok(5).as_ref()
516-
&& e.ok(2).is_ok()
517-
&& let Ok(_v) = e.ok(4)
518-
&& let Ok(_) = e.err(3) => {}
519-
_ => {
520-
e.mark(9);
521-
}
522-
};
523-
e.assert(9);
524-
}
525-
526422
fn main() {
527423
t_bindings();
528424
t_tuples();
@@ -540,13 +436,9 @@ fn main() {
540436
t_if_let_else_tailexpr();
541437
t_if_let_nested_then();
542438
t_let_else_chained_then();
543-
t_if_let_chains_then();
544-
t_guard_if_let_chains_then();
545439
t_if_let_nested_else();
546440
t_if_let_nested_then_else();
547441
t_let_else_chained_then_else();
548-
t_if_let_chains_then_else();
549-
t_guard_if_let_chains_then_else();
550442
}
551443

552444
// # Test scaffolding

0 commit comments

Comments
 (0)