Skip to content

Commit 4107322

Browse files
committed
Error on resetted binding mode in edition 2024
1 parent 4abbdfa commit 4107322

File tree

12 files changed

+270
-48
lines changed

12 files changed

+270
-48
lines changed

compiler/rustc_hir_typeck/src/pat.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -692,10 +692,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
692692
BindingMode(def_br, Mutability::Mut)
693693
} else {
694694
// `mut` resets binding mode on edition <= 2021
695-
self.typeck_results
695+
*self
696+
.typeck_results
696697
.borrow_mut()
697698
.rust_2024_migration_desugared_pats_mut()
698-
.insert(pat_info.top_info.hir_id);
699+
.entry(pat_info.top_info.hir_id)
700+
.or_default() |= pat.span.at_least_rust_2024();
699701
BindingMode(ByRef::No, Mutability::Mut)
700702
}
701703
}
@@ -2206,14 +2208,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
22062208
}
22072209
} else {
22082210
// Reset binding mode on old editions
2209-
22102211
if pat_info.binding_mode != ByRef::No {
22112212
pat_info.binding_mode = ByRef::No;
2212-
2213-
self.typeck_results
2213+
*self
2214+
.typeck_results
22142215
.borrow_mut()
22152216
.rust_2024_migration_desugared_pats_mut()
2216-
.insert(pat_info.top_info.hir_id);
2217+
.entry(pat_info.top_info.hir_id)
2218+
.or_default() |= pat.span.at_least_rust_2024();
22172219
}
22182220
}
22192221

@@ -2264,6 +2266,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
22642266
(err, err)
22652267
}
22662268
};
2269+
22672270
self.check_pat(inner, inner_ty, pat_info);
22682271
ref_ty
22692272
}

compiler/rustc_hir_typeck/src/writeback.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -640,7 +640,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
640640

641641
#[instrument(skip(self), level = "debug")]
642642
fn visit_rust_2024_migration_desugared_pats(&mut self, hir_id: hir::HirId) {
643-
if self
643+
if let Some(is_hard_error) = self
644644
.fcx
645645
.typeck_results
646646
.borrow_mut()
@@ -650,7 +650,9 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
650650
debug!(
651651
"node is a pat whose match ergonomics are desugared by the Rust 2024 migration lint"
652652
);
653-
self.typeck_results.rust_2024_migration_desugared_pats_mut().insert(hir_id);
653+
self.typeck_results
654+
.rust_2024_migration_desugared_pats_mut()
655+
.insert(hir_id, is_hard_error);
654656
}
655657
}
656658

compiler/rustc_lint_defs/src/builtin.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1650,7 +1650,7 @@ declare_lint! {
16501650
/// ### Example
16511651
///
16521652
/// ```rust,edition2021
1653-
/// #![feature(ref_pat_eat_one_layer_2024)]
1653+
/// #![feature(min_match_ergonomics_2024)]
16541654
/// #![warn(rust_2024_incompatible_pat)]
16551655
///
16561656
/// if let Some(&a) = &Some(&0u8) {
@@ -1671,7 +1671,7 @@ declare_lint! {
16711671
pub RUST_2024_INCOMPATIBLE_PAT,
16721672
Allow,
16731673
"detects patterns whose meaning will change in Rust 2024",
1674-
@feature_gate = ref_pat_eat_one_layer_2024;
1674+
@feature_gate = min_match_ergonomics_2024;
16751675
// FIXME uncomment below upon stabilization
16761676
/*@future_incompatible = FutureIncompatibleInfo {
16771677
reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),

compiler/rustc_middle/src/ty/typeck_results.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,10 @@ pub struct TypeckResults<'tcx> {
7979
/// Stores the actual binding mode for all instances of [`BindingMode`].
8080
pat_binding_modes: ItemLocalMap<BindingMode>,
8181

82-
/// Top-level patterns whose match ergonomics need to be desugared
83-
/// by the Rust 2021 -> 2024 migration lint.
84-
rust_2024_migration_desugared_pats: ItemLocalSet,
82+
/// Top-level patterns whose match ergonomics need to be desugared by the Rust 2021 -> 2024
83+
/// migration lint. The boolean indicates whether the emitted diagnostic should be a hard error
84+
/// (if any of the incompatible pattern elements are in edition 2024).
85+
rust_2024_migration_desugared_pats: ItemLocalMap<bool>,
8586

8687
/// Stores the types which were implicitly dereferenced in pattern binding modes
8788
/// for later usage in THIR lowering. For example,
@@ -437,15 +438,15 @@ impl<'tcx> TypeckResults<'tcx> {
437438
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments }
438439
}
439440

440-
pub fn rust_2024_migration_desugared_pats(&self) -> LocalSetInContext<'_> {
441-
LocalSetInContext {
441+
pub fn rust_2024_migration_desugared_pats(&self) -> LocalTableInContext<'_, bool> {
442+
LocalTableInContext {
442443
hir_owner: self.hir_owner,
443444
data: &self.rust_2024_migration_desugared_pats,
444445
}
445446
}
446447

447-
pub fn rust_2024_migration_desugared_pats_mut(&mut self) -> LocalSetInContextMut<'_> {
448-
LocalSetInContextMut {
448+
pub fn rust_2024_migration_desugared_pats_mut(&mut self) -> LocalTableInContextMut<'_, bool> {
449+
LocalTableInContextMut {
449450
hir_owner: self.hir_owner,
450451
data: &mut self.rust_2024_migration_desugared_pats,
451452
}

compiler/rustc_mir_build/src/errors.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -983,6 +983,8 @@ pub(crate) struct Rust2024IncompatiblePat {
983983

984984
pub(crate) struct Rust2024IncompatiblePatSugg {
985985
pub(crate) suggestion: Vec<(Span, String)>,
986+
/// Whether the incompatibility is a hard error because a relevant span is in edition 2024.
987+
pub(crate) is_hard_error: bool,
986988
}
987989

988990
impl Subdiagnostic for Rust2024IncompatiblePatSugg {

compiler/rustc_mir_build/src/thir/pattern/mod.rs

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,18 +48,30 @@ pub(super) fn pat_from_hir<'a, 'tcx>(
4848
typeck_results,
4949
rust_2024_migration_suggestion: typeck_results
5050
.rust_2024_migration_desugared_pats()
51-
.contains(pat.hir_id)
52-
.then_some(Rust2024IncompatiblePatSugg { suggestion: Vec::new() }),
51+
.get(pat.hir_id)
52+
.map(|&is_hard_error| Rust2024IncompatiblePatSugg {
53+
suggestion: Vec::new(),
54+
is_hard_error,
55+
}),
5356
};
5457
let result = pcx.lower_pattern(pat);
5558
debug!("pat_from_hir({:?}) = {:?}", pat, result);
5659
if let Some(sugg) = pcx.rust_2024_migration_suggestion {
57-
tcx.emit_node_span_lint(
58-
lint::builtin::RUST_2024_INCOMPATIBLE_PAT,
59-
pat.hir_id,
60-
pat.span,
61-
Rust2024IncompatiblePat { sugg },
62-
);
60+
if tcx.features().min_match_ergonomics_2024 && sugg.is_hard_error {
61+
let mut err = tcx.dcx().struct_span_err(
62+
pat.span,
63+
"patterns are not allowed to reset the default binding mode in rust 2024",
64+
);
65+
err.subdiagnostic(sugg);
66+
err.emit();
67+
} else {
68+
tcx.emit_node_span_lint(
69+
lint::builtin::RUST_2024_INCOMPATIBLE_PAT,
70+
pat.hir_id,
71+
pat.span,
72+
Rust2024IncompatiblePat { sugg },
73+
);
74+
}
6375
}
6476
result
6577
}

tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.fixed

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//@ run-rustfix
33
//@ rustfix-only-machine-applicable
44
//@ aux-build:migration_lint_macros.rs
5-
#![feature(mut_ref, ref_pat_eat_one_layer_2024)]
5+
#![feature(mut_ref, min_match_ergonomics_2024)]
66
#![allow(incomplete_features, unused)]
77
#![deny(rust_2024_incompatible_pat)]
88

@@ -114,14 +114,13 @@ fn main() {
114114
assert_type_eq(c, &&0u32);
115115
}
116116

117-
#[warn(rust_2024_incompatible_pat)]
118117
match &(Some(0), Some(0)) {
119118
// The two patterns are the same syntactically, but because they're defined in different
120119
// editions they don't mean the same thing.
121-
(Some(mut x), migration_lint_macros::mixed_edition_pat!(y)) => {
122-
//~^ WARN: the semantics of this pattern will change in edition 2024
120+
&(Some(mut x), migration_lint_macros::mixed_edition_pat!(y)) => {
121+
//~^ ERROR: patterns are not allowed to reset the default binding mode
123122
assert_type_eq(x, 0u32);
124-
assert_type_eq(y, &0u32);
123+
assert_type_eq(y, 0u32);
125124
}
126125
_ => {}
127126
}

tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//@ run-rustfix
33
//@ rustfix-only-machine-applicable
44
//@ aux-build:migration_lint_macros.rs
5-
#![feature(mut_ref, ref_pat_eat_one_layer_2024)]
5+
#![feature(mut_ref, min_match_ergonomics_2024)]
66
#![allow(incomplete_features, unused)]
77
#![deny(rust_2024_incompatible_pat)]
88

@@ -114,14 +114,13 @@ fn main() {
114114
assert_type_eq(c, &&0u32);
115115
}
116116

117-
#[warn(rust_2024_incompatible_pat)]
118117
match &(Some(0), Some(0)) {
119118
// The two patterns are the same syntactically, but because they're defined in different
120119
// editions they don't mean the same thing.
121120
(Some(mut x), migration_lint_macros::mixed_edition_pat!(y)) => {
122-
//~^ WARN: the semantics of this pattern will change in edition 2024
121+
//~^ ERROR: patterns are not allowed to reset the default binding mode
123122
assert_type_eq(x, 0u32);
124-
assert_type_eq(y, &0u32);
123+
assert_type_eq(y, 0u32);
125124
}
126125
_ => {}
127126
}

tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -120,21 +120,13 @@ help: desugar the match ergonomics
120120
LL | if let &Struct { a: &Some(a), b: &Some(&b), c: &Some(ref c) } =
121121
| + + + +++
122122

123-
warning: the semantics of this pattern will change in edition 2024
124-
--> $DIR/migration_lint.rs:121:9
123+
error: patterns are not allowed to reset the default binding mode in rust 2024
124+
--> $DIR/migration_lint.rs:120:9
125125
|
126126
LL | (Some(mut x), migration_lint_macros::mixed_edition_pat!(y)) => {
127-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
128-
|
129-
note: the lint level is defined here
130-
--> $DIR/migration_lint.rs:117:12
131-
|
132-
LL | #[warn(rust_2024_incompatible_pat)]
133-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
134-
help: desugar the match ergonomics
135-
|
136-
LL | &(Some(mut x), migration_lint_macros::mixed_edition_pat!(ref y)) => {
137-
| + +++
127+
| -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
128+
| |
129+
| help: desugar the match ergonomics: `&`
138130

139-
error: aborting due to 13 previous errors; 1 warning emitted
131+
error: aborting due to 14 previous errors
140132

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//@ check-fail
2+
//@ edition: 2024
3+
//@ compile-flags: -Zunstable-options
4+
// gate-test-min_match_ergonomics_2024
5+
#![feature(min_match_ergonomics_2024)]
6+
#![allow(incomplete_features)]
7+
#![deny(rust_2024_incompatible_pat)]
8+
9+
fn main() {}
10+
11+
#[derive(Copy, Clone)]
12+
struct T;
13+
14+
struct Foo {
15+
f: &'static (u8,),
16+
}
17+
18+
macro_rules! test_pat_on_type {
19+
($($tt:tt)*) => {
20+
const _: () = {
21+
// Define a new function to ensure all cases are tested independently.
22+
fn foo($($tt)*) {}
23+
};
24+
};
25+
}
26+
27+
test_pat_on_type![(&x,): &(T,)]; //~ ERROR mismatched types
28+
test_pat_on_type![(&x,): &(&T,)]; //~ ERROR patterns are not allowed to reset the default binding mode
29+
test_pat_on_type![(&x,): &(&mut T,)]; //~ ERROR mismatched types
30+
test_pat_on_type![(&mut x,): &(&T,)]; //~ ERROR mismatched types
31+
test_pat_on_type![(&mut x,): &(&mut T,)]; //~ ERROR patterns are not allowed to reset the default binding mode
32+
test_pat_on_type![(&x,): &&mut &(T,)]; //~ ERROR mismatched types
33+
test_pat_on_type![Foo { f: (&x,) }: Foo]; //~ ERROR mismatched types
34+
test_pat_on_type![Foo { f: (&x,) }: &mut Foo]; //~ ERROR mismatched types
35+
test_pat_on_type![Foo { f: &(x,) }: &Foo]; //~ ERROR patterns are not allowed to reset the default binding mode
36+
test_pat_on_type![(mut x,): &(T,)]; //~ ERROR patterns are not allowed to reset the default binding mode
37+
test_pat_on_type![(ref x,): &(T,)];
38+
test_pat_on_type![(ref mut x,): &mut (T,)];
39+
40+
fn get<X>() -> X {
41+
unimplemented!()
42+
}
43+
44+
// Make sure this works even when the underlying type is inferred. This test passes on rust stable.
45+
fn infer<X: Copy>() -> X {
46+
match &get() {
47+
(&x,) => x, //~ ERROR patterns are not allowed to reset the default binding mode
48+
}
49+
}

0 commit comments

Comments
 (0)