1
Fork 0

Error on resetted binding mode in edition 2024

This commit is contained in:
Nadrieril 2024-10-06 20:47:06 +02:00
parent 4abbdfa1c9
commit 4107322766
12 changed files with 270 additions and 48 deletions

View file

@ -692,10 +692,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
BindingMode(def_br, Mutability::Mut) BindingMode(def_br, Mutability::Mut)
} else { } else {
// `mut` resets binding mode on edition <= 2021 // `mut` resets binding mode on edition <= 2021
self.typeck_results *self
.typeck_results
.borrow_mut() .borrow_mut()
.rust_2024_migration_desugared_pats_mut() .rust_2024_migration_desugared_pats_mut()
.insert(pat_info.top_info.hir_id); .entry(pat_info.top_info.hir_id)
.or_default() |= pat.span.at_least_rust_2024();
BindingMode(ByRef::No, Mutability::Mut) BindingMode(ByRef::No, Mutability::Mut)
} }
} }
@ -2206,14 +2208,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
} else { } else {
// Reset binding mode on old editions // Reset binding mode on old editions
if pat_info.binding_mode != ByRef::No { if pat_info.binding_mode != ByRef::No {
pat_info.binding_mode = ByRef::No; pat_info.binding_mode = ByRef::No;
*self
self.typeck_results .typeck_results
.borrow_mut() .borrow_mut()
.rust_2024_migration_desugared_pats_mut() .rust_2024_migration_desugared_pats_mut()
.insert(pat_info.top_info.hir_id); .entry(pat_info.top_info.hir_id)
.or_default() |= pat.span.at_least_rust_2024();
} }
} }
@ -2264,6 +2266,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(err, err) (err, err)
} }
}; };
self.check_pat(inner, inner_ty, pat_info); self.check_pat(inner, inner_ty, pat_info);
ref_ty ref_ty
} }

View file

@ -640,7 +640,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
#[instrument(skip(self), level = "debug")] #[instrument(skip(self), level = "debug")]
fn visit_rust_2024_migration_desugared_pats(&mut self, hir_id: hir::HirId) { fn visit_rust_2024_migration_desugared_pats(&mut self, hir_id: hir::HirId) {
if self if let Some(is_hard_error) = self
.fcx .fcx
.typeck_results .typeck_results
.borrow_mut() .borrow_mut()
@ -650,7 +650,9 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
debug!( debug!(
"node is a pat whose match ergonomics are desugared by the Rust 2024 migration lint" "node is a pat whose match ergonomics are desugared by the Rust 2024 migration lint"
); );
self.typeck_results.rust_2024_migration_desugared_pats_mut().insert(hir_id); self.typeck_results
.rust_2024_migration_desugared_pats_mut()
.insert(hir_id, is_hard_error);
} }
} }

View file

@ -1650,7 +1650,7 @@ declare_lint! {
/// ### Example /// ### Example
/// ///
/// ```rust,edition2021 /// ```rust,edition2021
/// #![feature(ref_pat_eat_one_layer_2024)] /// #![feature(min_match_ergonomics_2024)]
/// #![warn(rust_2024_incompatible_pat)] /// #![warn(rust_2024_incompatible_pat)]
/// ///
/// if let Some(&a) = &Some(&0u8) { /// if let Some(&a) = &Some(&0u8) {
@ -1671,7 +1671,7 @@ declare_lint! {
pub RUST_2024_INCOMPATIBLE_PAT, pub RUST_2024_INCOMPATIBLE_PAT,
Allow, Allow,
"detects patterns whose meaning will change in Rust 2024", "detects patterns whose meaning will change in Rust 2024",
@feature_gate = ref_pat_eat_one_layer_2024; @feature_gate = min_match_ergonomics_2024;
// FIXME uncomment below upon stabilization // FIXME uncomment below upon stabilization
/*@future_incompatible = FutureIncompatibleInfo { /*@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024), reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),

View file

@ -79,9 +79,10 @@ pub struct TypeckResults<'tcx> {
/// Stores the actual binding mode for all instances of [`BindingMode`]. /// Stores the actual binding mode for all instances of [`BindingMode`].
pat_binding_modes: ItemLocalMap<BindingMode>, pat_binding_modes: ItemLocalMap<BindingMode>,
/// Top-level patterns whose match ergonomics need to be desugared /// Top-level patterns whose match ergonomics need to be desugared by the Rust 2021 -> 2024
/// by the Rust 2021 -> 2024 migration lint. /// migration lint. The boolean indicates whether the emitted diagnostic should be a hard error
rust_2024_migration_desugared_pats: ItemLocalSet, /// (if any of the incompatible pattern elements are in edition 2024).
rust_2024_migration_desugared_pats: ItemLocalMap<bool>,
/// Stores the types which were implicitly dereferenced in pattern binding modes /// Stores the types which were implicitly dereferenced in pattern binding modes
/// for later usage in THIR lowering. For example, /// for later usage in THIR lowering. For example,
@ -437,15 +438,15 @@ impl<'tcx> TypeckResults<'tcx> {
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments } LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments }
} }
pub fn rust_2024_migration_desugared_pats(&self) -> LocalSetInContext<'_> { pub fn rust_2024_migration_desugared_pats(&self) -> LocalTableInContext<'_, bool> {
LocalSetInContext { LocalTableInContext {
hir_owner: self.hir_owner, hir_owner: self.hir_owner,
data: &self.rust_2024_migration_desugared_pats, data: &self.rust_2024_migration_desugared_pats,
} }
} }
pub fn rust_2024_migration_desugared_pats_mut(&mut self) -> LocalSetInContextMut<'_> { pub fn rust_2024_migration_desugared_pats_mut(&mut self) -> LocalTableInContextMut<'_, bool> {
LocalSetInContextMut { LocalTableInContextMut {
hir_owner: self.hir_owner, hir_owner: self.hir_owner,
data: &mut self.rust_2024_migration_desugared_pats, data: &mut self.rust_2024_migration_desugared_pats,
} }

View file

@ -983,6 +983,8 @@ pub(crate) struct Rust2024IncompatiblePat {
pub(crate) struct Rust2024IncompatiblePatSugg { pub(crate) struct Rust2024IncompatiblePatSugg {
pub(crate) suggestion: Vec<(Span, String)>, pub(crate) suggestion: Vec<(Span, String)>,
/// Whether the incompatibility is a hard error because a relevant span is in edition 2024.
pub(crate) is_hard_error: bool,
} }
impl Subdiagnostic for Rust2024IncompatiblePatSugg { impl Subdiagnostic for Rust2024IncompatiblePatSugg {

View file

@ -48,18 +48,30 @@ pub(super) fn pat_from_hir<'a, 'tcx>(
typeck_results, typeck_results,
rust_2024_migration_suggestion: typeck_results rust_2024_migration_suggestion: typeck_results
.rust_2024_migration_desugared_pats() .rust_2024_migration_desugared_pats()
.contains(pat.hir_id) .get(pat.hir_id)
.then_some(Rust2024IncompatiblePatSugg { suggestion: Vec::new() }), .map(|&is_hard_error| Rust2024IncompatiblePatSugg {
suggestion: Vec::new(),
is_hard_error,
}),
}; };
let result = pcx.lower_pattern(pat); let result = pcx.lower_pattern(pat);
debug!("pat_from_hir({:?}) = {:?}", pat, result); debug!("pat_from_hir({:?}) = {:?}", pat, result);
if let Some(sugg) = pcx.rust_2024_migration_suggestion { if let Some(sugg) = pcx.rust_2024_migration_suggestion {
tcx.emit_node_span_lint( if tcx.features().min_match_ergonomics_2024 && sugg.is_hard_error {
lint::builtin::RUST_2024_INCOMPATIBLE_PAT, let mut err = tcx.dcx().struct_span_err(
pat.hir_id, pat.span,
pat.span, "patterns are not allowed to reset the default binding mode in rust 2024",
Rust2024IncompatiblePat { sugg }, );
); err.subdiagnostic(sugg);
err.emit();
} else {
tcx.emit_node_span_lint(
lint::builtin::RUST_2024_INCOMPATIBLE_PAT,
pat.hir_id,
pat.span,
Rust2024IncompatiblePat { sugg },
);
}
} }
result result
} }

View file

@ -2,7 +2,7 @@
//@ run-rustfix //@ run-rustfix
//@ rustfix-only-machine-applicable //@ rustfix-only-machine-applicable
//@ aux-build:migration_lint_macros.rs //@ aux-build:migration_lint_macros.rs
#![feature(mut_ref, ref_pat_eat_one_layer_2024)] #![feature(mut_ref, min_match_ergonomics_2024)]
#![allow(incomplete_features, unused)] #![allow(incomplete_features, unused)]
#![deny(rust_2024_incompatible_pat)] #![deny(rust_2024_incompatible_pat)]
@ -114,14 +114,13 @@ fn main() {
assert_type_eq(c, &&0u32); assert_type_eq(c, &&0u32);
} }
#[warn(rust_2024_incompatible_pat)]
match &(Some(0), Some(0)) { match &(Some(0), Some(0)) {
// The two patterns are the same syntactically, but because they're defined in different // The two patterns are the same syntactically, but because they're defined in different
// editions they don't mean the same thing. // editions they don't mean the same thing.
(Some(mut x), migration_lint_macros::mixed_edition_pat!(y)) => { &(Some(mut x), migration_lint_macros::mixed_edition_pat!(y)) => {
//~^ WARN: the semantics of this pattern will change in edition 2024 //~^ ERROR: patterns are not allowed to reset the default binding mode
assert_type_eq(x, 0u32); assert_type_eq(x, 0u32);
assert_type_eq(y, &0u32); assert_type_eq(y, 0u32);
} }
_ => {} _ => {}
} }

View file

@ -2,7 +2,7 @@
//@ run-rustfix //@ run-rustfix
//@ rustfix-only-machine-applicable //@ rustfix-only-machine-applicable
//@ aux-build:migration_lint_macros.rs //@ aux-build:migration_lint_macros.rs
#![feature(mut_ref, ref_pat_eat_one_layer_2024)] #![feature(mut_ref, min_match_ergonomics_2024)]
#![allow(incomplete_features, unused)] #![allow(incomplete_features, unused)]
#![deny(rust_2024_incompatible_pat)] #![deny(rust_2024_incompatible_pat)]
@ -114,14 +114,13 @@ fn main() {
assert_type_eq(c, &&0u32); assert_type_eq(c, &&0u32);
} }
#[warn(rust_2024_incompatible_pat)]
match &(Some(0), Some(0)) { match &(Some(0), Some(0)) {
// The two patterns are the same syntactically, but because they're defined in different // The two patterns are the same syntactically, but because they're defined in different
// editions they don't mean the same thing. // editions they don't mean the same thing.
(Some(mut x), migration_lint_macros::mixed_edition_pat!(y)) => { (Some(mut x), migration_lint_macros::mixed_edition_pat!(y)) => {
//~^ WARN: the semantics of this pattern will change in edition 2024 //~^ ERROR: patterns are not allowed to reset the default binding mode
assert_type_eq(x, 0u32); assert_type_eq(x, 0u32);
assert_type_eq(y, &0u32); assert_type_eq(y, 0u32);
} }
_ => {} _ => {}
} }

View file

@ -120,21 +120,13 @@ help: desugar the match ergonomics
LL | if let &Struct { a: &Some(a), b: &Some(&b), c: &Some(ref c) } = LL | if let &Struct { a: &Some(a), b: &Some(&b), c: &Some(ref c) } =
| + + + +++ | + + + +++
warning: the semantics of this pattern will change in edition 2024 error: patterns are not allowed to reset the default binding mode in rust 2024
--> $DIR/migration_lint.rs:121:9 --> $DIR/migration_lint.rs:120:9
| |
LL | (Some(mut x), migration_lint_macros::mixed_edition_pat!(y)) => { LL | (Some(mut x), migration_lint_macros::mixed_edition_pat!(y)) => {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| | |
note: the lint level is defined here | help: desugar the match ergonomics: `&`
--> $DIR/migration_lint.rs:117:12
|
LL | #[warn(rust_2024_incompatible_pat)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
help: desugar the match ergonomics
|
LL | &(Some(mut x), migration_lint_macros::mixed_edition_pat!(ref y)) => {
| + +++
error: aborting due to 13 previous errors; 1 warning emitted error: aborting due to 14 previous errors

View file

@ -0,0 +1,49 @@
//@ check-fail
//@ edition: 2024
//@ compile-flags: -Zunstable-options
// gate-test-min_match_ergonomics_2024
#![feature(min_match_ergonomics_2024)]
#![allow(incomplete_features)]
#![deny(rust_2024_incompatible_pat)]
fn main() {}
#[derive(Copy, Clone)]
struct T;
struct Foo {
f: &'static (u8,),
}
macro_rules! test_pat_on_type {
($($tt:tt)*) => {
const _: () = {
// Define a new function to ensure all cases are tested independently.
fn foo($($tt)*) {}
};
};
}
test_pat_on_type![(&x,): &(T,)]; //~ ERROR mismatched types
test_pat_on_type![(&x,): &(&T,)]; //~ ERROR patterns are not allowed to reset the default binding mode
test_pat_on_type![(&x,): &(&mut T,)]; //~ ERROR mismatched types
test_pat_on_type![(&mut x,): &(&T,)]; //~ ERROR mismatched types
test_pat_on_type![(&mut x,): &(&mut T,)]; //~ ERROR patterns are not allowed to reset the default binding mode
test_pat_on_type![(&x,): &&mut &(T,)]; //~ ERROR mismatched types
test_pat_on_type![Foo { f: (&x,) }: Foo]; //~ ERROR mismatched types
test_pat_on_type![Foo { f: (&x,) }: &mut Foo]; //~ ERROR mismatched types
test_pat_on_type![Foo { f: &(x,) }: &Foo]; //~ ERROR patterns are not allowed to reset the default binding mode
test_pat_on_type![(mut x,): &(T,)]; //~ ERROR patterns are not allowed to reset the default binding mode
test_pat_on_type![(ref x,): &(T,)];
test_pat_on_type![(ref mut x,): &mut (T,)];
fn get<X>() -> X {
unimplemented!()
}
// Make sure this works even when the underlying type is inferred. This test passes on rust stable.
fn infer<X: Copy>() -> X {
match &get() {
(&x,) => x, //~ ERROR patterns are not allowed to reset the default binding mode
}
}

View file

@ -0,0 +1,144 @@
error[E0308]: mismatched types
--> $DIR/min_match_ergonomics_fail.rs:27:20
|
LL | test_pat_on_type![(&x,): &(T,)];
| ^^ ----- expected due to this
| |
| expected `T`, found `&_`
|
= note: expected struct `T`
found reference `&_`
help: consider removing `&` from the pattern
|
LL - test_pat_on_type![(&x,): &(T,)];
LL + test_pat_on_type![(x,): &(T,)];
|
error[E0308]: mismatched types
--> $DIR/min_match_ergonomics_fail.rs:29:20
|
LL | test_pat_on_type![(&x,): &(&mut T,)];
| ^^ ---------- expected due to this
| |
| types differ in mutability
|
= note: expected mutable reference `&mut T`
found reference `&_`
help: consider removing `&` from the pattern
|
LL - test_pat_on_type![(&x,): &(&mut T,)];
LL + test_pat_on_type![(x,): &(&mut T,)];
|
error[E0308]: mismatched types
--> $DIR/min_match_ergonomics_fail.rs:30:20
|
LL | test_pat_on_type![(&mut x,): &(&T,)];
| ^^^^^^ ------ expected due to this
| |
| types differ in mutability
|
= note: expected reference `&T`
found mutable reference `&mut _`
note: to declare a mutable binding use: `mut x`
--> $DIR/min_match_ergonomics_fail.rs:30:20
|
LL | test_pat_on_type![(&mut x,): &(&T,)];
| ^^^^^^
help: consider removing `&mut` from the pattern
|
LL - test_pat_on_type![(&mut x,): &(&T,)];
LL + test_pat_on_type![(x,): &(&T,)];
|
error[E0308]: mismatched types
--> $DIR/min_match_ergonomics_fail.rs:32:20
|
LL | test_pat_on_type![(&x,): &&mut &(T,)];
| ^^ ----------- expected due to this
| |
| expected `T`, found `&_`
|
= note: expected struct `T`
found reference `&_`
help: consider removing `&` from the pattern
|
LL - test_pat_on_type![(&x,): &&mut &(T,)];
LL + test_pat_on_type![(x,): &&mut &(T,)];
|
error[E0308]: mismatched types
--> $DIR/min_match_ergonomics_fail.rs:33:29
|
LL | test_pat_on_type![Foo { f: (&x,) }: Foo];
| ^^ --- expected due to this
| |
| expected `u8`, found `&_`
|
= note: expected type `u8`
found reference `&_`
help: consider removing `&` from the pattern
|
LL - test_pat_on_type![Foo { f: (&x,) }: Foo];
LL + test_pat_on_type![Foo { f: (x,) }: Foo];
|
error[E0308]: mismatched types
--> $DIR/min_match_ergonomics_fail.rs:34:29
|
LL | test_pat_on_type![Foo { f: (&x,) }: &mut Foo];
| ^^ -------- expected due to this
| |
| expected `u8`, found `&_`
|
= note: expected type `u8`
found reference `&_`
help: consider removing `&` from the pattern
|
LL - test_pat_on_type![Foo { f: (&x,) }: &mut Foo];
LL + test_pat_on_type![Foo { f: (x,) }: &mut Foo];
|
error: patterns are not allowed to reset the default binding mode in rust 2024
--> $DIR/min_match_ergonomics_fail.rs:28:19
|
LL | test_pat_on_type![(&x,): &(&T,)];
| -^^^^
| |
| help: desugar the match ergonomics: `&`
error: patterns are not allowed to reset the default binding mode in rust 2024
--> $DIR/min_match_ergonomics_fail.rs:31:19
|
LL | test_pat_on_type![(&mut x,): &(&mut T,)];
| -^^^^^^^^
| |
| help: desugar the match ergonomics: `&`
error: patterns are not allowed to reset the default binding mode in rust 2024
--> $DIR/min_match_ergonomics_fail.rs:35:19
|
LL | test_pat_on_type![Foo { f: &(x,) }: &Foo];
| -^^^^^^^^^^^^^^^
| |
| help: desugar the match ergonomics: `&`
error: patterns are not allowed to reset the default binding mode in rust 2024
--> $DIR/min_match_ergonomics_fail.rs:36:19
|
LL | test_pat_on_type![(mut x,): &(T,)];
| -^^^^^^^
| |
| help: desugar the match ergonomics: `&`
error: patterns are not allowed to reset the default binding mode in rust 2024
--> $DIR/min_match_ergonomics_fail.rs:47:9
|
LL | (&x,) => x,
| -^^^^
| |
| help: desugar the match ergonomics: `&`
error: aborting due to 11 previous errors
For more information about this error, try `rustc --explain E0308`.

View file

@ -0,0 +1,19 @@
//@ revisions: normal min_match_ergonomics
//@ check-pass
#![cfg_attr(min_match_ergonomics, feature(min_match_ergonomics_2024))]
#![allow(incomplete_features)]
fn main() {}
// Tests type equality in a way that avoids coercing `&&T` to `&T`.
trait Eq<T> {}
impl<T> Eq<T> for T {}
fn assert_type_eq<T, U: Eq<T>>(_: T, _: U) {}
#[derive(Copy, Clone)]
struct T;
fn test() {
let (x,) = &(&T,);
assert_type_eq(x, &&T);
}