Match ergonomics 2024: migration lint

Unfortunately, we can't always offer a machine-applicable suggestion when there are subpatterns from macro expansion.

Co-Authored-By: Guillaume Boisseau <Nadrieril@users.noreply.github.com>
This commit is contained in:
Jules Bertholet 2024-05-02 19:55:03 -04:00
parent 686bfc4c42
commit 9d92a7f355
No known key found for this signature in database
GPG key ID: 32034DAFC38C1BFC
17 changed files with 409 additions and 116 deletions

View file

@ -4367,6 +4367,7 @@ dependencies = [
"rustc_hir",
"rustc_index",
"rustc_infer",
"rustc_lint",
"rustc_macros",
"rustc_middle",
"rustc_pattern_analysis",

View file

@ -46,10 +46,6 @@ hir_typeck_ctor_is_private = tuple struct constructor `{$def}` is private
hir_typeck_deref_is_empty = this expression `Deref`s to `{$deref_ty}` which implements `is_empty`
hir_typeck_dereferencing_mut_binding = dereferencing `mut` binding
.label = `mut` dereferences the type of this binding
.help = this will change in edition 2024
hir_typeck_expected_default_return_type = expected `()` because of default return type
hir_typeck_expected_return_type = expected `{$expected}` because of return type

View file

@ -651,10 +651,3 @@ pub enum SuggestBoxingForReturnImplTrait {
ends: Vec<Span>,
},
}
#[derive(LintDiagnostic)]
#[diag(hir_typeck_dereferencing_mut_binding)]
pub struct DereferencingMutBinding {
#[label]
#[help]
pub span: Span,
}

View file

@ -73,21 +73,23 @@ struct TopInfo<'tcx> {
/// found type `std::result::Result<_, _>`
/// ```
span: Option<Span>,
/// The [`HirId`] of the top-level pattern.
hir_id: HirId,
}
#[derive(Copy, Clone)]
struct PatInfo<'tcx, 'a> {
binding_mode: ByRef,
max_ref_mutbl: MutblCap,
top_info: TopInfo<'tcx>,
decl_origin: Option<DeclOrigin<'a>>,
top_info: &'a TopInfo<'tcx>,
decl_origin: Option<DeclOrigin<'tcx>>,
/// The depth of current pattern
current_depth: u32,
}
impl<'tcx> FnCtxt<'_, 'tcx> {
fn pattern_cause(&self, ti: TopInfo<'tcx>, cause_span: Span) -> ObligationCause<'tcx> {
fn pattern_cause(&self, ti: &TopInfo<'tcx>, cause_span: Span) -> ObligationCause<'tcx> {
let code = ObligationCauseCode::Pattern {
span: ti.span,
root_ty: ti.expected,
@ -101,7 +103,7 @@ fn demand_eqtype_pat_diag(
cause_span: Span,
expected: Ty<'tcx>,
actual: Ty<'tcx>,
ti: TopInfo<'tcx>,
ti: &TopInfo<'tcx>,
) -> Option<Diag<'tcx>> {
let mut diag =
self.demand_eqtype_with_origin(&self.pattern_cause(ti, cause_span), expected, actual)?;
@ -118,7 +120,7 @@ fn demand_eqtype_pat(
cause_span: Span,
expected: Ty<'tcx>,
actual: Ty<'tcx>,
ti: TopInfo<'tcx>,
ti: &TopInfo<'tcx>,
) {
if let Some(err) = self.demand_eqtype_pat_diag(cause_span, expected, actual, ti) {
err.emit();
@ -199,11 +201,11 @@ pub(crate) fn check_pat_top(
origin_expr: Option<&'tcx hir::Expr<'tcx>>,
decl_origin: Option<DeclOrigin<'tcx>>,
) {
let info = TopInfo { expected, origin_expr, span };
let info = TopInfo { expected, origin_expr, span, hir_id: pat.hir_id };
let pat_info = PatInfo {
binding_mode: ByRef::No,
max_ref_mutbl: MutblCap::Mut,
top_info: info,
top_info: &info,
decl_origin,
current_depth: 0,
};
@ -463,7 +465,7 @@ fn check_pat_lit(
span: Span,
lt: &hir::Expr<'tcx>,
expected: Ty<'tcx>,
ti: TopInfo<'tcx>,
ti: &TopInfo<'tcx>,
) -> Ty<'tcx> {
// We've already computed the type above (when checking for a non-ref pat),
// so avoid computing it again.
@ -533,7 +535,7 @@ fn check_pat_range(
lhs: Option<&'tcx hir::Expr<'tcx>>,
rhs: Option<&'tcx hir::Expr<'tcx>>,
expected: Ty<'tcx>,
ti: TopInfo<'tcx>,
ti: &TopInfo<'tcx>,
) -> Ty<'tcx> {
let calc_side = |opt_expr: Option<&'tcx hir::Expr<'tcx>>| match opt_expr {
None => None,
@ -671,18 +673,16 @@ fn check_pat_ident(
// Determine the binding mode...
let bm = match user_bind_annot {
// `mut` resets binding mode on edition <= 2021
BindingMode(ByRef::No, Mutability::Mut)
if !(pat.span.at_least_rust_2024()
&& self.tcx.features().mut_preserve_binding_mode_2024)
&& matches!(def_br, ByRef::Yes(_)) =>
{
// `mut x` resets the binding mode in edition <= 2021.
self.tcx.emit_node_span_lint(
rustc_lint::builtin::DEREFERENCING_MUT_BINDING,
pat.hir_id,
pat.span,
errors::DereferencingMutBinding { span: pat.span },
);
self.typeck_results
.borrow_mut()
.rust_2024_migration_desugared_pats_mut()
.insert(pat_info.top_info.hir_id);
BindingMode(ByRef::No, Mutability::Mut)
}
BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl),
@ -754,7 +754,7 @@ fn check_binding_alt_eq_ty(
span: Span,
var_id: HirId,
ty: Ty<'tcx>,
ti: TopInfo<'tcx>,
ti: &TopInfo<'tcx>,
) {
let var_ty = self.local_ty(span, var_id);
if let Some(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) {
@ -996,7 +996,7 @@ fn check_pat_path(
qpath: &hir::QPath<'_>,
path_resolution: (Res, Option<LoweredTy<'tcx>>, &'tcx [hir::PathSegment<'tcx>]),
expected: Ty<'tcx>,
ti: TopInfo<'tcx>,
ti: &TopInfo<'tcx>,
) -> Ty<'tcx> {
let tcx = self.tcx;
@ -2178,8 +2178,17 @@ enum MatchErgonomicsMode {
}
} else {
// Reset binding mode on old editions
pat_info.binding_mode = ByRef::No;
pat_info.max_ref_mutbl = MutblCap::Mut
if pat_info.binding_mode != ByRef::No {
pat_info.binding_mode = ByRef::No;
self.typeck_results
.borrow_mut()
.rust_2024_migration_desugared_pats_mut()
.insert(pat_info.top_info.hir_id);
}
pat_info.max_ref_mutbl = MutblCap::Mut;
}
let tcx = self.tcx;

View file

@ -346,6 +346,7 @@ fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
_ => {}
};
self.visit_rust_2024_migration_desugared_pats(p.hir_id);
self.visit_skipped_ref_pats(p.hir_id);
self.visit_pat_adjustments(p.span, p.hir_id);
@ -655,6 +656,22 @@ fn visit_adjustments(&mut self, span: Span, hir_id: HirId) {
}
}
#[instrument(skip(self), level = "debug")]
fn visit_rust_2024_migration_desugared_pats(&mut self, hir_id: hir::HirId) {
if self
.fcx
.typeck_results
.borrow_mut()
.rust_2024_migration_desugared_pats_mut()
.remove(hir_id)
{
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);
}
}
#[instrument(skip(self, span), level = "debug")]
fn visit_pat_adjustments(&mut self, span: Span, hir_id: HirId) {
let adjustment = self.fcx.typeck_results.borrow_mut().pat_adjustments_mut().remove(hir_id);

View file

@ -38,7 +38,6 @@
DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
DEPRECATED_IN_FUTURE,
DEPRECATED_WHERE_CLAUSE_LOCATION,
DEREFERENCING_MUT_BINDING,
DUPLICATE_MACRO_ATTRIBUTES,
ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT,
ELIDED_LIFETIMES_IN_PATHS,
@ -90,6 +89,7 @@
RUST_2021_INCOMPATIBLE_OR_PATTERNS,
RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX,
RUST_2021_PRELUDE_COLLISIONS,
RUST_2024_INCOMPATIBLE_PAT,
SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
SINGLE_USE_LIFETIMES,
SOFT_UNSTABLE,
@ -1630,34 +1630,34 @@
}
declare_lint! {
/// The `dereferencing_mut_binding` lint detects a `mut x` pattern that resets the binding mode,
/// as this behavior will change in rust 2024.
/// The `rust_2024_incompatible_pat` lint
/// detects patterns whose meaning will change in the Rust 2024 edition.
///
/// ### Example
///
/// ```rust
/// # #![warn(dereferencing_mut_binding)]
/// let x = Some(123u32);
/// let _y = match &x {
/// Some(mut x) => {
/// x += 1;
/// x
/// }
/// None => 0,
/// };
/// ```rust,edition2021
/// #![feature(ref_pat_eat_one_layer_2024)]
/// #![warn(rust_2024_incompatible_pat)]
///
/// if let Some(&a) = &Some(&0u8) {
/// let _: u8 = a;
/// }
/// if let Some(mut _a) = &mut Some(0u8) {
/// _a = 7u8;
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Without the `mut`, `x` would have type `&u32`. Pre-2024, adding `mut` makes `x` have type
/// `u32`, which was deemed surprising. After edition 2024, adding `mut` will not change the
/// type of `x`. This lint warns users of editions before 2024 to update their code.
pub DEREFERENCING_MUT_BINDING,
/// In Rust 2024 and above, the `mut` keyword does not reset the pattern binding mode,
/// and nor do `&` or `&mut` patterns. The lint will suggest code that
/// has the same meaning in all editions.
pub RUST_2024_INCOMPATIBLE_PAT,
Allow,
"detects `mut x` bindings that change the type of `x`",
@feature_gate = sym::mut_preserve_binding_mode_2024;
"detects patterns whose meaning will change in Rust 2024",
@feature_gate = sym::ref_pat_eat_one_layer_2024;
// FIXME uncomment below upon stabilization
/*@future_incompatible = FutureIncompatibleInfo {
reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),

View file

@ -79,6 +79,10 @@ pub struct TypeckResults<'tcx> {
/// Stores the actual binding mode for all instances of [`BindingMode`].
pat_binding_modes: ItemLocalMap<BindingMode>,
/// Top-level patterns whose match ergonomics need to be desugared
/// by the Rust 2021 -> 2024 migration lint.
rust_2024_migration_desugared_pats: ItemLocalSet,
/// Stores the types which were implicitly dereferenced in pattern binding modes
/// for later usage in THIR lowering. For example,
///
@ -229,6 +233,7 @@ pub fn new(hir_owner: OwnerId) -> TypeckResults<'tcx> {
adjustments: Default::default(),
pat_binding_modes: Default::default(),
pat_adjustments: Default::default(),
rust_2024_migration_desugared_pats: Default::default(),
skipped_ref_pats: Default::default(),
closure_kind_origins: Default::default(),
liberated_fn_sigs: Default::default(),
@ -432,6 +437,20 @@ pub fn pat_adjustments_mut(&mut self) -> LocalTableInContextMut<'_, Vec<Ty<'tcx>
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments }
}
pub fn rust_2024_migration_desugared_pats(&self) -> LocalSetInContext<'_> {
LocalSetInContext {
hir_owner: self.hir_owner,
data: &self.rust_2024_migration_desugared_pats,
}
}
pub fn rust_2024_migration_desugared_pats_mut(&mut self) -> LocalSetInContextMut<'_> {
LocalSetInContextMut {
hir_owner: self.hir_owner,
data: &mut self.rust_2024_migration_desugared_pats,
}
}
pub fn skipped_ref_pats(&self) -> LocalSetInContext<'_> {
LocalSetInContext { hir_owner: self.hir_owner, data: &self.skipped_ref_pats }
}

View file

@ -16,6 +16,7 @@ rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_hir = { path = "../rustc_hir" }
rustc_index = { path = "../rustc_index" }
rustc_infer = { path = "../rustc_infer" }
rustc_lint = { path = "../rustc_lint" }
rustc_macros = { path = "../rustc_macros" }
rustc_middle = { path = "../rustc_middle" }
rustc_pattern_analysis = { path = "../rustc_pattern_analysis" }

View file

@ -267,6 +267,8 @@ 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_rustc_box_attribute_error = `#[rustc_box]` attribute used incorrectly
.attributes = no other attributes may be applied
.not_box = `#[rustc_box]` may only be applied to a `Box::new()` call

View file

@ -950,3 +950,30 @@ pub enum RustcBoxAttrReason {
#[note(mir_build_missing_box)]
MissingBox,
}
#[derive(LintDiagnostic)]
#[diag(mir_build_rust_2024_incompatible_pat)]
pub struct Rust2024IncompatiblePat {
#[subdiagnostic]
pub sugg: Rust2024IncompatiblePatSugg,
}
pub struct Rust2024IncompatiblePatSugg {
pub suggestion: Vec<(Span, String)>,
}
impl Subdiagnostic for Rust2024IncompatiblePatSugg {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_f: &F,
) {
let applicability =
if self.suggestion.iter().all(|(span, _)| span.can_be_used_for_suggestions()) {
Applicability::MachineApplicable
} else {
Applicability::MaybeIncorrect
};
diag.multipart_suggestion("desugar the match ergonomics", self.suggestion, applicability);
}
}

View file

@ -11,8 +11,9 @@
use rustc_errors::codes::*;
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
use rustc_hir::{self as hir, RangeEnd};
use rustc_hir::{self as hir, ByRef, Mutability, RangeEnd};
use rustc_index::Idx;
use rustc_lint as lint;
use rustc_middle::mir::interpret::{ErrorHandled, GlobalId, LitToConstError, LitToConstInput};
use rustc_middle::mir::{self, Const};
use rustc_middle::thir::{
@ -30,6 +31,9 @@ struct PatCtxt<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
typeck_results: &'a ty::TypeckResults<'tcx>,
/// Used by the Rust 2024 migration lint.
rust_2024_migration_suggestion: Option<Rust2024IncompatiblePatSugg>,
}
pub(super) fn pat_from_hir<'a, 'tcx>(
@ -38,9 +42,25 @@ pub(super) fn pat_from_hir<'a, 'tcx>(
typeck_results: &'a ty::TypeckResults<'tcx>,
pat: &'tcx hir::Pat<'tcx>,
) -> Box<Pat<'tcx>> {
let mut pcx = PatCtxt { tcx, param_env, typeck_results };
let mut pcx = PatCtxt {
tcx,
param_env,
typeck_results,
rust_2024_migration_suggestion: typeck_results
.rust_2024_migration_desugared_pats()
.contains(pat.hir_id)
.then_some(Rust2024IncompatiblePatSugg { suggestion: Vec::new() }),
};
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 },
);
}
result
}
@ -73,17 +93,38 @@ fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
}
_ => self.lower_pattern_unadjusted(pat),
};
self.typeck_results.pat_adjustments().get(pat.hir_id).unwrap_or(&vec![]).iter().rev().fold(
unadjusted_pat,
|pat: Box<_>, ref_ty| {
debug!("{:?}: wrapping pattern with type {:?}", pat, ref_ty);
Box::new(Pat {
span: pat.span,
ty: *ref_ty,
kind: PatKind::Deref { subpattern: pat },
let adjustments: &[Ty<'tcx>] =
self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(&[], |v| &**v);
let adjusted_pat = adjustments.iter().rev().fold(unadjusted_pat, |thir_pat, ref_ty| {
debug!("{:?}: wrapping pattern with type {:?}", thir_pat, ref_ty);
Box::new(Pat {
span: thir_pat.span,
ty: *ref_ty,
kind: PatKind::Deref { subpattern: thir_pat },
})
});
if let Some(s) = &mut self.rust_2024_migration_suggestion
&& !adjustments.is_empty()
{
let suggestion_str: String = adjustments
.iter()
.map(|ref_ty| {
let &ty::Ref(_, _, mutbl) = ref_ty.kind() else {
span_bug!(pat.span, "pattern implicitly dereferences a non-ref type");
};
match mutbl {
ty::Mutability::Not => "&",
ty::Mutability::Mut => "&mut ",
}
})
},
)
.collect();
s.suggestion.push((pat.span.shrink_to_lo(), suggestion_str));
};
adjusted_pat
}
fn lower_pattern_range_endpoint(
@ -272,7 +313,7 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tc
PatKind::Deref { subpattern: self.lower_pattern(subpattern) }
}
hir::PatKind::Slice(prefix, ref slice, suffix) => {
hir::PatKind::Slice(prefix, slice, suffix) => {
self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix)
}
@ -284,7 +325,7 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tc
PatKind::Leaf { subpatterns }
}
hir::PatKind::Binding(_, id, ident, ref sub) => {
hir::PatKind::Binding(explicit_ba, id, ident, sub) => {
if let Some(ident_span) = ident.span.find_ancestor_inside(span) {
span = span.with_hi(ident_span.hi());
}
@ -295,6 +336,20 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tc
.get(pat.hir_id)
.expect("missing binding mode");
if let Some(s) = &mut self.rust_2024_migration_suggestion
&& explicit_ba.0 == ByRef::No
&& let ByRef::Yes(mutbl) = mode.0
{
let sugg_str = match mutbl {
Mutability::Not => "ref ",
Mutability::Mut => "ref mut ",
};
s.suggestion.push((
pat.span.with_lo(ident.span.lo()).shrink_to_lo(),
sugg_str.to_owned(),
))
}
// A ref x pattern is the same node used for x, and as such it has
// x's type, which is &T, where we want T (the type being matched).
let var_ty = ty;
@ -366,10 +421,7 @@ fn lower_patterns(&mut self, pats: &'tcx [hir::Pat<'tcx>]) -> Box<[Box<Pat<'tcx>
pats.iter().map(|p| self.lower_pattern(p)).collect()
}
fn lower_opt_pattern(
&mut self,
pat: &'tcx Option<&'tcx hir::Pat<'tcx>>,
) -> Option<Box<Pat<'tcx>>> {
fn lower_opt_pattern(&mut self, pat: Option<&'tcx hir::Pat<'tcx>>) -> Option<Box<Pat<'tcx>>> {
pat.map(|p| self.lower_pattern(p))
}
@ -378,7 +430,7 @@ fn slice_or_array_pattern(
span: Span,
ty: Ty<'tcx>,
prefix: &'tcx [hir::Pat<'tcx>],
slice: &'tcx Option<&'tcx hir::Pat<'tcx>>,
slice: Option<&'tcx hir::Pat<'tcx>>,
suffix: &'tcx [hir::Pat<'tcx>],
) -> PatKind<'tcx> {
let prefix = self.lower_patterns(prefix);

View file

@ -0,0 +1,12 @@
//@ edition: 2024
//@ compile-flags: -Z unstable-options
// This contains a binding in edition 2024, so if matched with a reference binding mode it will end
// up with a `mut ref mut` binding mode. We use this to test the migration lint on patterns with
// mixed editions.
#[macro_export]
macro_rules! mixed_edition_pat {
($foo:ident) => {
Some(mut $foo)
};
}

View file

@ -0,0 +1,57 @@
//@ edition: 2021
//@ run-rustfix
//@ rustfix-only-machine-applicable
//@ aux-build:match_ergonomics_2024_macros.rs
#![feature(mut_preserve_binding_mode_2024, 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;
}
_ => {}
}
}

View file

@ -0,0 +1,57 @@
//@ edition: 2021
//@ run-rustfix
//@ rustfix-only-machine-applicable
//@ aux-build:match_ergonomics_2024_macros.rs
#![feature(mut_preserve_binding_mode_2024, 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;
}
_ => {}
}
}

View file

@ -0,0 +1,97 @@
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

View file

@ -1,16 +0,0 @@
//@ edition: 2021
#![feature(mut_preserve_binding_mode_2024)]
#![allow(incomplete_features, unused)]
#![forbid(dereferencing_mut_binding)]
struct Foo(u8);
fn main() {
let Foo(mut a) = &Foo(0);
//~^ ERROR: dereferencing `mut` binding
a = 42;
let Foo(mut a) = &mut Foo(0);
//~^ ERROR: dereferencing `mut` binding
a = 42;
}

View file

@ -1,31 +0,0 @@
error: dereferencing `mut` binding
--> $DIR/mut_preserve_binding_mode_2024_lint.rs:9:13
|
LL | let Foo(mut a) = &Foo(0);
| ^^^^^ `mut` dereferences the type of this binding
|
help: this will change in edition 2024
--> $DIR/mut_preserve_binding_mode_2024_lint.rs:9:13
|
LL | let Foo(mut a) = &Foo(0);
| ^^^^^
note: the lint level is defined here
--> $DIR/mut_preserve_binding_mode_2024_lint.rs:4:11
|
LL | #![forbid(dereferencing_mut_binding)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: dereferencing `mut` binding
--> $DIR/mut_preserve_binding_mode_2024_lint.rs:13:13
|
LL | let Foo(mut a) = &mut Foo(0);
| ^^^^^ `mut` dereferences the type of this binding
|
help: this will change in edition 2024
--> $DIR/mut_preserve_binding_mode_2024_lint.rs:13:13
|
LL | let Foo(mut a) = &mut Foo(0);
| ^^^^^
error: aborting due to 2 previous errors