Auto merge of #124914 - nnethercote:rm-extern-crate-rustc_middle, r=saethlin
Remove `#[macro_use] extern crate rustc middle` from numerous crates
Because explicit importing of macros via `use` items is nicer (more standard and readable) than implicit importing via `#[macro_use]`. This PR mops up some cases I didn't get to in #124511.
r? `@saethlin`
diff --git a/Cargo.lock b/Cargo.lock
index 1cf2592..df4e4f3 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4369,6 +4369,7 @@
"rustc_hir",
"rustc_index",
"rustc_infer",
+ "rustc_lint",
"rustc_macros",
"rustc_middle",
"rustc_pattern_analysis",
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 2c17682..b7bdb2e 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1238,7 +1238,11 @@
if let Some((init, els)) = loc.kind.init_else_opt() {
self.nbsp();
self.word_space("=");
- self.print_expr(init, FixupContext::default());
+ self.print_expr_cond_paren(
+ init,
+ els.is_some() && classify::expr_trailing_brace(init).is_some(),
+ FixupContext::default(),
+ );
if let Some(els) = els {
self.cbox(INDENT_UNIT);
self.ibox(INDENT_UNIT);
diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl
index 0560d0d..72b95a9 100644
--- a/compiler/rustc_hir_typeck/messages.ftl
+++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -46,10 +46,6 @@
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
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index ba8f246..f250b90 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -651,10 +651,3 @@
ends: Vec<Span>,
},
}
-#[derive(LintDiagnostic)]
-#[diag(hir_typeck_dereferencing_mut_binding)]
-pub struct DereferencingMutBinding {
- #[label]
- #[help]
- pub span: Span,
-}
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index ae1ca54..b9b220d 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -74,21 +74,23 @@
/// 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,
@@ -102,7 +104,7 @@
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)?;
@@ -119,7 +121,7 @@
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();
@@ -200,11 +202,11 @@
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,
};
@@ -464,7 +466,7 @@
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.
@@ -534,7 +536,7 @@
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,
@@ -672,18 +674,16 @@
// 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),
@@ -755,7 +755,7 @@
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) {
@@ -997,7 +997,7 @@
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;
@@ -2179,8 +2179,17 @@
}
} 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;
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index fe717fa..f798dee 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -347,6 +347,7 @@
_ => {}
};
+ 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);
@@ -656,6 +657,22 @@
}
}
+ #[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);
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index eea3ca4..5369454 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -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),
diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs
index 41f417d..24e3e62 100644
--- a/compiler/rustc_middle/src/ty/typeck_results.rs
+++ b/compiler/rustc_middle/src/ty/typeck_results.rs
@@ -79,6 +79,10 @@
/// 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 @@
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 @@
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 }
}
diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml
index 6618e4f..77f2723 100644
--- a/compiler/rustc_mir_build/Cargo.toml
+++ b/compiler/rustc_mir_build/Cargo.toml
@@ -16,6 +16,7 @@
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" }
diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl
index 34440c6..0bb44db 100644
--- a/compiler/rustc_mir_build/messages.ftl
+++ b/compiler/rustc_mir_build/messages.ftl
@@ -267,6 +267,8 @@
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
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index f67113a..e2a2846 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -950,3 +950,30 @@
#[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);
+ }
+}
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 0fe29fb..dc845b3 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -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::{
@@ -31,6 +32,9 @@
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>(
@@ -39,9 +43,25 @@
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
}
@@ -74,17 +94,38 @@
}
_ => 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(
@@ -273,7 +314,7 @@
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)
}
@@ -285,7 +326,7 @@
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());
}
@@ -296,6 +337,20 @@
.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;
@@ -367,10 +422,7 @@
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))
}
@@ -379,7 +431,7 @@
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);
diff --git a/tests/ui/macros/stringify.rs b/tests/ui/macros/stringify.rs
index 472cb4d..6b215ba 100644
--- a/tests/ui/macros/stringify.rs
+++ b/tests/ui/macros/stringify.rs
@@ -675,6 +675,11 @@
"let (a, b): (u32, u32) = (1, 2);",
"let (a, b): (u32, u32) = (1, 2)"
);
+ c2!(stmt,
+ [ let _ = f() else { return; } ],
+ "let _ = f() else { return; };",
+ "let _ = f() else { return; }",
+ );
macro_rules! c2_let_expr_minus_one {
([ $expr:expr ], $stmt_expected:expr, $tokens_expected:expr $(,)?) => {
c2!(stmt, [ let _ = $expr - 1 ], $stmt_expected, $tokens_expected);
@@ -685,6 +690,16 @@
"let _ = match void {} - 1;",
"let _ = match void {} - 1",
);
+ macro_rules! c2_let_expr_else_return {
+ ([ $expr:expr ], $stmt_expected:expr, $tokens_expected:expr $(,)?) => {
+ c2!(stmt, [ let _ = $expr else { return; } ], $stmt_expected, $tokens_expected);
+ };
+ }
+ c2_let_expr_else_return!(
+ [ f() ],
+ "let _ = f() else { return; };",
+ "let _ = f() else { return; }",
+ );
// StmtKind::Item
c1!(stmt, [ struct S; ], "struct S;");
diff --git a/tests/ui/pattern/auxiliary/match_ergonomics_2024_macros.rs b/tests/ui/pattern/auxiliary/match_ergonomics_2024_macros.rs
new file mode 100644
index 0000000..0b70e44
--- /dev/null
+++ b/tests/ui/pattern/auxiliary/match_ergonomics_2024_macros.rs
@@ -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)
+ };
+}
diff --git a/tests/ui/pattern/match_ergonomics_2024.fixed b/tests/ui/pattern/match_ergonomics_2024.fixed
new file mode 100644
index 0000000..d8dbcb2
--- /dev/null
+++ b/tests/ui/pattern/match_ergonomics_2024.fixed
@@ -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;
+ }
+ _ => {}
+ }
+}
diff --git a/tests/ui/pattern/match_ergonomics_2024.rs b/tests/ui/pattern/match_ergonomics_2024.rs
new file mode 100644
index 0000000..38dc0c8
--- /dev/null
+++ b/tests/ui/pattern/match_ergonomics_2024.rs
@@ -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;
+ }
+ _ => {}
+ }
+}
diff --git a/tests/ui/pattern/match_ergonomics_2024.stderr b/tests/ui/pattern/match_ergonomics_2024.stderr
new file mode 100644
index 0000000..1184443
--- /dev/null
+++ b/tests/ui/pattern/match_ergonomics_2024.stderr
@@ -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
+
diff --git a/tests/ui/pattern/mut_preserve_binding_mode_2024_lint.rs b/tests/ui/pattern/mut_preserve_binding_mode_2024_lint.rs
deleted file mode 100644
index 249f251..0000000
--- a/tests/ui/pattern/mut_preserve_binding_mode_2024_lint.rs
+++ /dev/null
@@ -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;
-}
diff --git a/tests/ui/pattern/mut_preserve_binding_mode_2024_lint.stderr b/tests/ui/pattern/mut_preserve_binding_mode_2024_lint.stderr
deleted file mode 100644
index e8d11ac..0000000
--- a/tests/ui/pattern/mut_preserve_binding_mode_2024_lint.stderr
+++ /dev/null
@@ -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
-
diff --git a/tests/ui/unpretty/pretty-let-else.rs b/tests/ui/unpretty/let-else-hir.rs
similarity index 100%
rename from tests/ui/unpretty/pretty-let-else.rs
rename to tests/ui/unpretty/let-else-hir.rs
diff --git a/tests/ui/unpretty/pretty-let-else.stdout b/tests/ui/unpretty/let-else-hir.stdout
similarity index 100%
rename from tests/ui/unpretty/pretty-let-else.stdout
rename to tests/ui/unpretty/let-else-hir.stdout
diff --git a/tests/ui/unpretty/let-else.rs b/tests/ui/unpretty/let-else.rs
new file mode 100644
index 0000000..4db6eca
--- /dev/null
+++ b/tests/ui/unpretty/let-else.rs
@@ -0,0 +1,11 @@
+//@ compile-flags: -Zunpretty=expanded
+//@ check-pass
+
+macro_rules! expr {
+ ($e:expr) => { $e };
+}
+
+fn main() {
+ let _ = expr!(1 + 1) else { return; };
+ let _ = expr!(loop {}) else { return; };
+}
diff --git a/tests/ui/unpretty/let-else.stdout b/tests/ui/unpretty/let-else.stdout
new file mode 100644
index 0000000..4bc4d9e
--- /dev/null
+++ b/tests/ui/unpretty/let-else.stdout
@@ -0,0 +1,15 @@
+#![feature(prelude_import)]
+#![no_std]
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
+#[macro_use]
+extern crate std;
+//@ compile-flags: -Zunpretty=expanded
+//@ check-pass
+
+macro_rules! expr { ($e:expr) => { $e }; }
+
+fn main() {
+ let _ = 1 + 1 else { return; };
+ let _ = (loop {}) else { return; };
+}