diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index fb78da0a86c..423ffced897 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -690,16 +690,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { BindingMode(def_br, Mutability::Mut) } else { - // `mut` resets binding mode on edition <= 2021 - self.typeck_results + // `mut` resets the binding mode on edition <= 2021 + *self + .typeck_results .borrow_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, mutbl) => BindingMode(def_br, mutbl), - BindingMode(ByRef::Yes(_), _) => user_bind_annot, + BindingMode(ByRef::Yes(_), _) => { + if matches!(def_br, ByRef::Yes(_)) { + // `ref`/`ref mut` overrides the binding mode on edition <= 2021 + *self + .typeck_results + .borrow_mut() + .rust_2024_migration_desugared_pats_mut() + .entry(pat_info.top_info.hir_id) + .or_default() |= pat.span.at_least_rust_2024(); + } + user_bind_annot + } }; if bm.0 == ByRef::Yes(Mutability::Mut) @@ -2204,14 +2217,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } else { // Reset binding mode on old editions - if pat_info.binding_mode != ByRef::No { pat_info.binding_mode = ByRef::No; - - self.typeck_results + *self + .typeck_results .borrow_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(); } } @@ -2262,6 +2275,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (err, err) } }; + self.check_pat(inner, inner_ty, pat_info); ref_ty } diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index b193b81f6de..d3d092be222 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -635,7 +635,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { #[instrument(skip(self), level = "debug")] fn visit_rust_2024_migration_desugared_pats(&mut self, hir_id: hir::HirId) { - if self + if let Some(is_hard_error) = self .fcx .typeck_results .borrow_mut() @@ -645,7 +645,9 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { debug!( "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); } } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index da603df9a9a..5f5b5514020 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1651,7 +1651,6 @@ declare_lint! { /// ### Example /// /// ```rust,edition2021 - /// #![feature(ref_pat_eat_one_layer_2024)] /// #![warn(rust_2024_incompatible_pat)] /// /// if let Some(&a) = &Some(&0u8) { @@ -1672,12 +1671,10 @@ declare_lint! { pub RUST_2024_INCOMPATIBLE_PAT, Allow, "detects patterns whose meaning will change in Rust 2024", - @feature_gate = ref_pat_eat_one_layer_2024; - // FIXME uncomment below upon stabilization - /*@future_incompatible = FutureIncompatibleInfo { + @future_incompatible = FutureIncompatibleInfo { reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024), reference: "123076", - };*/ + }; } declare_lint! { diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index c01d2120111..6aa2b2cd480 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -73,9 +73,10 @@ pub struct TypeckResults<'tcx> { /// Stores the actual binding mode for all instances of [`BindingMode`]. pat_binding_modes: ItemLocalMap, - /// Top-level patterns whose match ergonomics need to be desugared - /// by the Rust 2021 -> 2024 migration lint. - rust_2024_migration_desugared_pats: ItemLocalSet, + /// Top-level patterns whose match ergonomics need to be desugared by the Rust 2021 -> 2024 + /// migration lint. The boolean indicates whether the emitted diagnostic should be a hard error + /// (if any of the incompatible pattern elements are in edition 2024). + rust_2024_migration_desugared_pats: ItemLocalMap, /// Stores the types which were implicitly dereferenced in pattern binding modes /// for later usage in THIR lowering. For example, @@ -418,15 +419,15 @@ impl<'tcx> TypeckResults<'tcx> { LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments } } - pub fn rust_2024_migration_desugared_pats(&self) -> LocalSetInContext<'_> { - LocalSetInContext { + pub fn rust_2024_migration_desugared_pats(&self) -> LocalTableInContext<'_, bool> { + LocalTableInContext { hir_owner: self.hir_owner, data: &self.rust_2024_migration_desugared_pats, } } - pub fn rust_2024_migration_desugared_pats_mut(&mut self) -> LocalSetInContextMut<'_> { - LocalSetInContextMut { + pub fn rust_2024_migration_desugared_pats_mut(&mut self) -> LocalTableInContextMut<'_, bool> { + LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.rust_2024_migration_desugared_pats, } diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index 1c4e9fd11cb..55149570dbc 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -265,7 +265,7 @@ mir_build_pointer_pattern = function pointers and raw pointers not derived from mir_build_privately_uninhabited = pattern `{$witness_1}` is currently uninhabited, but this variant contains private fields which may become inhabited in the future -mir_build_rust_2024_incompatible_pat = the semantics of this pattern will change in edition 2024 +mir_build_rust_2024_incompatible_pat = patterns are not allowed to reset the default binding mode in edition 2024 mir_build_rustc_box_attribute_error = `#[rustc_box]` attribute used incorrectly .attributes = no other attributes may be applied diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 42be7f9402e..00f65e0c7d0 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -983,6 +983,8 @@ pub(crate) struct Rust2024IncompatiblePat { pub(crate) struct Rust2024IncompatiblePatSugg { 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 { diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 04e921ecc2e..56e5156a91f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -25,6 +25,7 @@ use tracing::{debug, instrument}; pub(crate) use self::check_match::check_match; use crate::errors::*; +use crate::fluent_generated as fluent; use crate::thir::util::UserAnnotatedTyHelpers; struct PatCtxt<'a, 'tcx> { @@ -48,18 +49,28 @@ pub(super) fn pat_from_hir<'a, 'tcx>( typeck_results, rust_2024_migration_suggestion: typeck_results .rust_2024_migration_desugared_pats() - .contains(pat.hir_id) - .then_some(Rust2024IncompatiblePatSugg { suggestion: Vec::new() }), + .get(pat.hir_id) + .map(|&is_hard_error| Rust2024IncompatiblePatSugg { + suggestion: Vec::new(), + is_hard_error, + }), }; let result = pcx.lower_pattern(pat); debug!("pat_from_hir({:?}) = {:?}", pat, result); if let Some(sugg) = pcx.rust_2024_migration_suggestion { - tcx.emit_node_span_lint( - lint::builtin::RUST_2024_INCOMPATIBLE_PAT, - pat.hir_id, - pat.span, - Rust2024IncompatiblePat { sugg }, - ); + if sugg.is_hard_error { + let mut err = + tcx.dcx().struct_span_err(pat.span, fluent::mir_build_rust_2024_incompatible_pat); + 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 } diff --git a/tests/ui/pattern/match_ergonomics_2024.fixed b/tests/ui/pattern/match_ergonomics_2024.fixed deleted file mode 100644 index 1ec2b5a214b..00000000000 --- a/tests/ui/pattern/match_ergonomics_2024.fixed +++ /dev/null @@ -1,57 +0,0 @@ -//@ edition: 2021 -//@ run-rustfix -//@ rustfix-only-machine-applicable -//@ aux-build:match_ergonomics_2024_macros.rs -#![feature(mut_ref, ref_pat_eat_one_layer_2024)] -#![allow(incomplete_features, unused)] -#![deny(rust_2024_incompatible_pat)] - -extern crate match_ergonomics_2024_macros; - -struct Foo(u8); - -fn main() { - let &Foo(mut a) = &Foo(0); - //~^ ERROR: the semantics of this pattern will change in edition 2024 - a = 42; - - let &mut Foo(mut a) = &mut Foo(0); - //~^ ERROR: the semantics of this pattern will change in edition 2024 - a = 42; - - if let &&&&&Some(&_) = &&&&&Some(&0u8) {} - //~^ ERROR: the semantics of this pattern will change in edition 2024 - - if let &&&&&Some(&mut _) = &&&&&Some(&mut 0u8) {} - //~^ ERROR: the semantics of this pattern will change in edition 2024 - - if let &&&&&mut Some(&_) = &&&&&mut Some(&0u8) {} - //~^ ERROR: the semantics of this pattern will change in edition 2024 - - if let &mut Some(&mut Some(&mut Some(_))) = &mut Some(&mut Some(&mut Some(0u8))) {} - //~^ ERROR: the semantics of this pattern will change in edition 2024 - - if let &mut Some(&mut Some(&mut Some(ref mut _a))) = &mut Some(&mut Some(&mut Some(0u8))) {} - //~^ ERROR: the semantics of this pattern will change in edition 2024 - - struct Struct { - a: u32, - b: u32, - c: u32, - } - let s = Struct { a: 0, b: 0, c: 0 }; - let &Struct { ref a, mut b, ref c } = &s; - //~^ ERROR: the semantics of this pattern will change in edition 2024 - - #[warn(rust_2024_incompatible_pat)] - match &(Some(0), Some(0)) { - // The two patterns are the same syntactically, but because they're defined in different - // editions they don't mean the same thing. - (Some(mut _x), match_ergonomics_2024_macros::mixed_edition_pat!(_y)) => { - //~^ WARN: the semantics of this pattern will change in edition 2024 - _x = 4; - _y = &7; - } - _ => {} - } -} diff --git a/tests/ui/pattern/match_ergonomics_2024.rs b/tests/ui/pattern/match_ergonomics_2024.rs deleted file mode 100644 index c9f992c12d4..00000000000 --- a/tests/ui/pattern/match_ergonomics_2024.rs +++ /dev/null @@ -1,57 +0,0 @@ -//@ edition: 2021 -//@ run-rustfix -//@ rustfix-only-machine-applicable -//@ aux-build:match_ergonomics_2024_macros.rs -#![feature(mut_ref, ref_pat_eat_one_layer_2024)] -#![allow(incomplete_features, unused)] -#![deny(rust_2024_incompatible_pat)] - -extern crate match_ergonomics_2024_macros; - -struct Foo(u8); - -fn main() { - let Foo(mut a) = &Foo(0); - //~^ ERROR: the semantics of this pattern will change in edition 2024 - a = 42; - - let Foo(mut a) = &mut Foo(0); - //~^ ERROR: the semantics of this pattern will change in edition 2024 - a = 42; - - if let Some(&_) = &&&&&Some(&0u8) {} - //~^ ERROR: the semantics of this pattern will change in edition 2024 - - if let Some(&mut _) = &&&&&Some(&mut 0u8) {} - //~^ ERROR: the semantics of this pattern will change in edition 2024 - - if let Some(&_) = &&&&&mut Some(&0u8) {} - //~^ ERROR: the semantics of this pattern will change in edition 2024 - - if let Some(&mut Some(Some(_))) = &mut Some(&mut Some(&mut Some(0u8))) {} - //~^ ERROR: the semantics of this pattern will change in edition 2024 - - if let Some(&mut Some(Some(_a))) = &mut Some(&mut Some(&mut Some(0u8))) {} - //~^ ERROR: the semantics of this pattern will change in edition 2024 - - struct Struct { - a: u32, - b: u32, - c: u32, - } - let s = Struct { a: 0, b: 0, c: 0 }; - let Struct { a, mut b, c } = &s; - //~^ ERROR: the semantics of this pattern will change in edition 2024 - - #[warn(rust_2024_incompatible_pat)] - match &(Some(0), Some(0)) { - // The two patterns are the same syntactically, but because they're defined in different - // editions they don't mean the same thing. - (Some(mut _x), match_ergonomics_2024_macros::mixed_edition_pat!(_y)) => { - //~^ WARN: the semantics of this pattern will change in edition 2024 - _x = 4; - _y = &7; - } - _ => {} - } -} diff --git a/tests/ui/pattern/match_ergonomics_2024.stderr b/tests/ui/pattern/match_ergonomics_2024.stderr deleted file mode 100644 index 11844434ad2..00000000000 --- a/tests/ui/pattern/match_ergonomics_2024.stderr +++ /dev/null @@ -1,97 +0,0 @@ -error: the semantics of this pattern will change in edition 2024 - --> $DIR/match_ergonomics_2024.rs:14:9 - | -LL | let Foo(mut a) = &Foo(0); - | -^^^^^^^^^ - | | - | help: desugar the match ergonomics: `&` - | -note: the lint level is defined here - --> $DIR/match_ergonomics_2024.rs:7:9 - | -LL | #![deny(rust_2024_incompatible_pat)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: the semantics of this pattern will change in edition 2024 - --> $DIR/match_ergonomics_2024.rs:18:9 - | -LL | let Foo(mut a) = &mut Foo(0); - | -^^^^^^^^^ - | | - | help: desugar the match ergonomics: `&mut` - -error: the semantics of this pattern will change in edition 2024 - --> $DIR/match_ergonomics_2024.rs:22:12 - | -LL | if let Some(&_) = &&&&&Some(&0u8) {} - | -^^^^^^^ - | | - | help: desugar the match ergonomics: `&&&&&` - -error: the semantics of this pattern will change in edition 2024 - --> $DIR/match_ergonomics_2024.rs:25:12 - | -LL | if let Some(&mut _) = &&&&&Some(&mut 0u8) {} - | -^^^^^^^^^^^ - | | - | help: desugar the match ergonomics: `&&&&&` - -error: the semantics of this pattern will change in edition 2024 - --> $DIR/match_ergonomics_2024.rs:28:12 - | -LL | if let Some(&_) = &&&&&mut Some(&0u8) {} - | -^^^^^^^ - | | - | help: desugar the match ergonomics: `&&&&&mut` - -error: the semantics of this pattern will change in edition 2024 - --> $DIR/match_ergonomics_2024.rs:31:12 - | -LL | if let Some(&mut Some(Some(_))) = &mut Some(&mut Some(&mut Some(0u8))) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: desugar the match ergonomics - | -LL | if let &mut Some(&mut Some(&mut Some(_))) = &mut Some(&mut Some(&mut Some(0u8))) {} - | ++++ ++++ - -error: the semantics of this pattern will change in edition 2024 - --> $DIR/match_ergonomics_2024.rs:34:12 - | -LL | if let Some(&mut Some(Some(_a))) = &mut Some(&mut Some(&mut Some(0u8))) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: desugar the match ergonomics - | -LL | if let &mut Some(&mut Some(&mut Some(ref mut _a))) = &mut Some(&mut Some(&mut Some(0u8))) {} - | ++++ ++++ +++++++ - -error: the semantics of this pattern will change in edition 2024 - --> $DIR/match_ergonomics_2024.rs:43:9 - | -LL | let Struct { a, mut b, c } = &s; - | ^^^^^^^^^^^^^^^^^^^^^^ - | -help: desugar the match ergonomics - | -LL | let &Struct { ref a, mut b, ref c } = &s; - | + +++ +++ - -warning: the semantics of this pattern will change in edition 2024 - --> $DIR/match_ergonomics_2024.rs:50:9 - | -LL | (Some(mut _x), match_ergonomics_2024_macros::mixed_edition_pat!(_y)) => { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/match_ergonomics_2024.rs:46:12 - | -LL | #[warn(rust_2024_incompatible_pat)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: desugar the match ergonomics - | -LL | &(Some(mut _x), match_ergonomics_2024_macros::mixed_edition_pat!(ref _y)) => { - | + +++ - -error: aborting due to 8 previous errors; 1 warning emitted - diff --git a/tests/ui/pattern/auxiliary/match_ergonomics_2024_macros.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/auxiliary/migration_lint_macros.rs similarity index 100% rename from tests/ui/pattern/auxiliary/match_ergonomics_2024_macros.rs rename to tests/ui/pattern/rfc-3627-match-ergonomics-2024/auxiliary/migration_lint_macros.rs diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.fixed b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.fixed new file mode 100644 index 00000000000..086671e69cb --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.fixed @@ -0,0 +1,144 @@ +//@ edition: 2021 +//@ run-rustfix +//@ rustfix-only-machine-applicable +//@ aux-build:migration_lint_macros.rs +#![feature(mut_ref)] +#![allow(incomplete_features, unused)] +#![deny(rust_2024_incompatible_pat)] + +extern crate migration_lint_macros; + +struct Foo(T); + +// Tests type equality in a way that avoids coercing `&&T` to `&T`. +trait Eq {} +impl Eq for T {} +fn assert_type_eq>(_: T, _: U) {} + +fn main() { + let Foo(x) = &Foo(0); + assert_type_eq(x, &0u8); + + let Foo(x) = &mut Foo(0); + assert_type_eq(x, &mut 0u8); + + let &Foo(mut x) = &Foo(0); + //~^ ERROR: patterns are not allowed to reset the default binding mode + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(x, 0u8); + + let &mut Foo(mut x) = &mut Foo(0); + //~^ ERROR: patterns are not allowed to reset the default binding mode + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(x, 0u8); + + let &Foo(ref x) = &Foo(0); + //~^ ERROR: patterns are not allowed to reset the default binding mode + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(x, &0u8); + + let &mut Foo(ref x) = &mut Foo(0); + //~^ ERROR: patterns are not allowed to reset the default binding mode + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(x, &0u8); + + let &Foo(x) = &Foo(0); + assert_type_eq(x, 0u8); + + let &mut Foo(x) = &mut Foo(0); + assert_type_eq(x, 0u8); + + let &Foo(x) = &Foo(&0); + assert_type_eq(x, &0u8); + + let &mut Foo(x) = &mut Foo(&0); + assert_type_eq(x, &0u8); + + let &Foo(&x) = &Foo(&0); + //~^ ERROR: patterns are not allowed to reset the default binding mode + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(x, 0u8); + + let &Foo(&mut x) = &Foo(&mut 0); + //~^ ERROR: patterns are not allowed to reset the default binding mode + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(x, 0u8); + + let &mut Foo(&x) = &mut Foo(&0); + //~^ ERROR: patterns are not allowed to reset the default binding mode + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(x, 0u8); + + let &mut Foo(&mut x) = &mut Foo(&mut 0); + //~^ ERROR: patterns are not allowed to reset the default binding mode + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(x, 0u8); + + if let Some(x) = &&&&&Some(&0u8) { + assert_type_eq(x, &&0u8); + } + + if let &&&&&Some(&x) = &&&&&Some(&0u8) { + //~^ ERROR: patterns are not allowed to reset the default binding mode + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(x, 0u8); + } + + if let &&&&&Some(&mut x) = &&&&&Some(&mut 0u8) { + //~^ ERROR: patterns are not allowed to reset the default binding mode + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(x, 0u8); + } + + if let &&&&&mut Some(&x) = &&&&&mut Some(&0u8) { + //~^ ERROR: patterns are not allowed to reset the default binding mode + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(x, 0u8); + } + + if let &mut Some(&mut Some(&mut Some(ref mut x))) = &mut Some(&mut Some(&mut Some(0u8))) { + //~^ ERROR: patterns are not allowed to reset the default binding mode + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(x, &mut 0u8); + } + + struct Struct { + a: A, + b: B, + c: C, + } + + let &Struct { ref a, mut b, ref c } = &Struct { a: 0, b: 0, c: 0 }; + //~^ ERROR: patterns are not allowed to reset the default binding mode + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(a, &0u32); + assert_type_eq(b, 0u32); + + let &Struct { a: &a, ref b, ref c } = &Struct { a: &0, b: &0, c: &0 }; + //~^ ERROR: patterns are not allowed to reset the default binding mode + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(a, 0u32); + assert_type_eq(b, &&0u32); + assert_type_eq(c, &&0u32); + + if let &Struct { a: &Some(a), b: &Some(&b), c: &Some(ref c) } = + //~^ ERROR: patterns are not allowed to reset the default binding mode + //~| WARN: this changes meaning in Rust 2024 + &(Struct { a: &Some(&0), b: &Some(&0), c: &Some(&0) }) + { + assert_type_eq(a, &0u32); + assert_type_eq(b, 0u32); + assert_type_eq(c, &&0u32); + } + + match &(Some(0), Some(0)) { + // The two patterns are the same syntactically, but because they're defined in different + // editions they don't mean the same thing. + &(Some(mut x), migration_lint_macros::mixed_edition_pat!(y)) => { + //~^ ERROR: patterns are not allowed to reset the default binding mode + assert_type_eq(x, 0u32); + assert_type_eq(y, 0u32); + } + _ => {} + } +} diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.rs new file mode 100644 index 00000000000..acceafdb7ec --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.rs @@ -0,0 +1,144 @@ +//@ edition: 2021 +//@ run-rustfix +//@ rustfix-only-machine-applicable +//@ aux-build:migration_lint_macros.rs +#![feature(mut_ref)] +#![allow(incomplete_features, unused)] +#![deny(rust_2024_incompatible_pat)] + +extern crate migration_lint_macros; + +struct Foo(T); + +// Tests type equality in a way that avoids coercing `&&T` to `&T`. +trait Eq {} +impl Eq for T {} +fn assert_type_eq>(_: T, _: U) {} + +fn main() { + let Foo(x) = &Foo(0); + assert_type_eq(x, &0u8); + + let Foo(x) = &mut Foo(0); + assert_type_eq(x, &mut 0u8); + + let Foo(mut x) = &Foo(0); + //~^ ERROR: patterns are not allowed to reset the default binding mode + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(x, 0u8); + + let Foo(mut x) = &mut Foo(0); + //~^ ERROR: patterns are not allowed to reset the default binding mode + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(x, 0u8); + + let Foo(ref x) = &Foo(0); + //~^ ERROR: patterns are not allowed to reset the default binding mode + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(x, &0u8); + + let Foo(ref x) = &mut Foo(0); + //~^ ERROR: patterns are not allowed to reset the default binding mode + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(x, &0u8); + + let &Foo(x) = &Foo(0); + assert_type_eq(x, 0u8); + + let &mut Foo(x) = &mut Foo(0); + assert_type_eq(x, 0u8); + + let &Foo(x) = &Foo(&0); + assert_type_eq(x, &0u8); + + let &mut Foo(x) = &mut Foo(&0); + assert_type_eq(x, &0u8); + + let Foo(&x) = &Foo(&0); + //~^ ERROR: patterns are not allowed to reset the default binding mode + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(x, 0u8); + + let Foo(&mut x) = &Foo(&mut 0); + //~^ ERROR: patterns are not allowed to reset the default binding mode + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(x, 0u8); + + let Foo(&x) = &mut Foo(&0); + //~^ ERROR: patterns are not allowed to reset the default binding mode + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(x, 0u8); + + let Foo(&mut x) = &mut Foo(&mut 0); + //~^ ERROR: patterns are not allowed to reset the default binding mode + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(x, 0u8); + + if let Some(x) = &&&&&Some(&0u8) { + assert_type_eq(x, &&0u8); + } + + if let Some(&x) = &&&&&Some(&0u8) { + //~^ ERROR: patterns are not allowed to reset the default binding mode + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(x, 0u8); + } + + if let Some(&mut x) = &&&&&Some(&mut 0u8) { + //~^ ERROR: patterns are not allowed to reset the default binding mode + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(x, 0u8); + } + + if let Some(&x) = &&&&&mut Some(&0u8) { + //~^ ERROR: patterns are not allowed to reset the default binding mode + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(x, 0u8); + } + + if let Some(&mut Some(Some(x))) = &mut Some(&mut Some(&mut Some(0u8))) { + //~^ ERROR: patterns are not allowed to reset the default binding mode + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(x, &mut 0u8); + } + + struct Struct { + a: A, + b: B, + c: C, + } + + let Struct { a, mut b, c } = &Struct { a: 0, b: 0, c: 0 }; + //~^ ERROR: patterns are not allowed to reset the default binding mode + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(a, &0u32); + assert_type_eq(b, 0u32); + + let Struct { a: &a, b, ref c } = &Struct { a: &0, b: &0, c: &0 }; + //~^ ERROR: patterns are not allowed to reset the default binding mode + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(a, 0u32); + assert_type_eq(b, &&0u32); + assert_type_eq(c, &&0u32); + + if let Struct { a: &Some(a), b: Some(&b), c: Some(c) } = + //~^ ERROR: patterns are not allowed to reset the default binding mode + //~| WARN: this changes meaning in Rust 2024 + &(Struct { a: &Some(&0), b: &Some(&0), c: &Some(&0) }) + { + assert_type_eq(a, &0u32); + assert_type_eq(b, 0u32); + assert_type_eq(c, &&0u32); + } + + match &(Some(0), Some(0)) { + // The two patterns are the same syntactically, but because they're defined in different + // editions they don't mean the same thing. + (Some(mut x), migration_lint_macros::mixed_edition_pat!(y)) => { + //~^ ERROR: patterns are not allowed to reset the default binding mode + assert_type_eq(x, 0u32); + assert_type_eq(y, 0u32); + } + _ => {} + } +} diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr new file mode 100644 index 00000000000..1c9a469e6ee --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr @@ -0,0 +1,188 @@ +error: patterns are not allowed to reset the default binding mode in edition 2024 + --> $DIR/migration_lint.rs:25:9 + | +LL | let Foo(mut x) = &Foo(0); + | -^^^^^^^^^ + | | + | help: desugar the match ergonomics: `&` + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see 123076 +note: the lint level is defined here + --> $DIR/migration_lint.rs:7:9 + | +LL | #![deny(rust_2024_incompatible_pat)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: patterns are not allowed to reset the default binding mode in edition 2024 + --> $DIR/migration_lint.rs:30:9 + | +LL | let Foo(mut x) = &mut Foo(0); + | -^^^^^^^^^ + | | + | help: desugar the match ergonomics: `&mut` + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see 123076 + +error: patterns are not allowed to reset the default binding mode in edition 2024 + --> $DIR/migration_lint.rs:35:9 + | +LL | let Foo(ref x) = &Foo(0); + | -^^^^^^^^^ + | | + | help: desugar the match ergonomics: `&` + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see 123076 + +error: patterns are not allowed to reset the default binding mode in edition 2024 + --> $DIR/migration_lint.rs:40:9 + | +LL | let Foo(ref x) = &mut Foo(0); + | -^^^^^^^^^ + | | + | help: desugar the match ergonomics: `&mut` + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see 123076 + +error: patterns are not allowed to reset the default binding mode in edition 2024 + --> $DIR/migration_lint.rs:57:9 + | +LL | let Foo(&x) = &Foo(&0); + | -^^^^^^ + | | + | help: desugar the match ergonomics: `&` + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see 123076 + +error: patterns are not allowed to reset the default binding mode in edition 2024 + --> $DIR/migration_lint.rs:62:9 + | +LL | let Foo(&mut x) = &Foo(&mut 0); + | -^^^^^^^^^^ + | | + | help: desugar the match ergonomics: `&` + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see 123076 + +error: patterns are not allowed to reset the default binding mode in edition 2024 + --> $DIR/migration_lint.rs:67:9 + | +LL | let Foo(&x) = &mut Foo(&0); + | -^^^^^^ + | | + | help: desugar the match ergonomics: `&mut` + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see 123076 + +error: patterns are not allowed to reset the default binding mode in edition 2024 + --> $DIR/migration_lint.rs:72:9 + | +LL | let Foo(&mut x) = &mut Foo(&mut 0); + | -^^^^^^^^^^ + | | + | help: desugar the match ergonomics: `&mut` + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see 123076 + +error: patterns are not allowed to reset the default binding mode in edition 2024 + --> $DIR/migration_lint.rs:81:12 + | +LL | if let Some(&x) = &&&&&Some(&0u8) { + | -^^^^^^^ + | | + | help: desugar the match ergonomics: `&&&&&` + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see 123076 + +error: patterns are not allowed to reset the default binding mode in edition 2024 + --> $DIR/migration_lint.rs:87:12 + | +LL | if let Some(&mut x) = &&&&&Some(&mut 0u8) { + | -^^^^^^^^^^^ + | | + | help: desugar the match ergonomics: `&&&&&` + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see 123076 + +error: patterns are not allowed to reset the default binding mode in edition 2024 + --> $DIR/migration_lint.rs:93:12 + | +LL | if let Some(&x) = &&&&&mut Some(&0u8) { + | -^^^^^^^ + | | + | help: desugar the match ergonomics: `&&&&&mut` + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see 123076 + +error: patterns are not allowed to reset the default binding mode in edition 2024 + --> $DIR/migration_lint.rs:99:12 + | +LL | if let Some(&mut Some(Some(x))) = &mut Some(&mut Some(&mut Some(0u8))) { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see 123076 +help: desugar the match ergonomics + | +LL | if let &mut Some(&mut Some(&mut Some(ref mut x))) = &mut Some(&mut Some(&mut Some(0u8))) { + | ++++ ++++ +++++++ + +error: patterns are not allowed to reset the default binding mode in edition 2024 + --> $DIR/migration_lint.rs:111:9 + | +LL | let Struct { a, mut b, c } = &Struct { a: 0, b: 0, c: 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see 123076 +help: desugar the match ergonomics + | +LL | let &Struct { ref a, mut b, ref c } = &Struct { a: 0, b: 0, c: 0 }; + | + +++ +++ + +error: patterns are not allowed to reset the default binding mode in edition 2024 + --> $DIR/migration_lint.rs:117:9 + | +LL | let Struct { a: &a, b, ref c } = &Struct { a: &0, b: &0, c: &0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see 123076 +help: desugar the match ergonomics + | +LL | let &Struct { a: &a, ref b, ref c } = &Struct { a: &0, b: &0, c: &0 }; + | + +++ + +error: patterns are not allowed to reset the default binding mode in edition 2024 + --> $DIR/migration_lint.rs:124:12 + | +LL | if let Struct { a: &Some(a), b: Some(&b), c: Some(c) } = + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see 123076 +help: desugar the match ergonomics + | +LL | if let &Struct { a: &Some(a), b: &Some(&b), c: &Some(ref c) } = + | + + + +++ + +error: patterns are not allowed to reset the default binding mode in edition 2024 + --> $DIR/migration_lint.rs:137:9 + | +LL | (Some(mut x), migration_lint_macros::mixed_edition_pat!(y)) => { + | -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | help: desugar the match ergonomics: `&` + +error: aborting due to 16 previous errors + diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.rs new file mode 100644 index 00000000000..a822c90ab6e --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.rs @@ -0,0 +1,46 @@ +//@ check-fail +//@ edition: 2024 +//@ compile-flags: -Zunstable-options +#![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,)]; //~ ERROR patterns are not allowed to reset the default binding mode +test_pat_on_type![(ref mut x,): &mut (T,)]; //~ ERROR patterns are not allowed to reset the default binding mode + +fn get() -> X { + unimplemented!() +} + +// Make sure this works even when the underlying type is inferred. This test passes on rust stable. +fn infer() -> X { + match &get() { + (&x,) => x, //~ ERROR patterns are not allowed to reset the default binding mode + } +} diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.stderr new file mode 100644 index 00000000000..33e4f0021b7 --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.stderr @@ -0,0 +1,160 @@ +error[E0308]: mismatched types + --> $DIR/min_match_ergonomics_fail.rs:24: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:26: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:27: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:27: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:29: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:30: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:31: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 edition 2024 + --> $DIR/min_match_ergonomics_fail.rs:25: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 edition 2024 + --> $DIR/min_match_ergonomics_fail.rs:28: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 edition 2024 + --> $DIR/min_match_ergonomics_fail.rs:32: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 edition 2024 + --> $DIR/min_match_ergonomics_fail.rs:33: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 edition 2024 + --> $DIR/min_match_ergonomics_fail.rs:34:19 + | +LL | test_pat_on_type![(ref x,): &(T,)]; + | -^^^^^^^ + | | + | help: desugar the match ergonomics: `&` + +error: patterns are not allowed to reset the default binding mode in edition 2024 + --> $DIR/min_match_ergonomics_fail.rs:35:19 + | +LL | test_pat_on_type![(ref mut x,): &mut (T,)]; + | -^^^^^^^^^^^ + | | + | help: desugar the match ergonomics: `&mut` + +error: patterns are not allowed to reset the default binding mode in edition 2024 + --> $DIR/min_match_ergonomics_fail.rs:44:9 + | +LL | (&x,) => x, + | -^^^^ + | | + | help: desugar the match ergonomics: `&` + +error: aborting due to 13 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_success.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_success.rs new file mode 100644 index 00000000000..0fb448afca9 --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_success.rs @@ -0,0 +1,17 @@ +//@ check-pass +#![allow(incomplete_features)] + +fn main() {} + +// Tests type equality in a way that avoids coercing `&&T` to `&T`. +trait Eq {} +impl Eq for T {} +fn assert_type_eq>(_: T, _: U) {} + +#[derive(Copy, Clone)] +struct T; + +fn test() { + let (x,) = &(&T,); + assert_type_eq(x, &&T); +}