From cb0f584249e0b027a026eabf6bd4f7c7be16ada4 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Fri, 5 Dec 2025 16:13:08 +0000 Subject: [PATCH 1/2] Separate inline const in expr and in pat parsing This makes it obvious that inline const pat is removed (and the parsing is only preserved for better error message). --- compiler/rustc_parse/src/parser/expr.rs | 14 +++++++++++- compiler/rustc_parse/src/parser/mod.rs | 24 -------------------- compiler/rustc_parse/src/parser/pat.rs | 18 +++++++++++++-- tests/ui/inline-const/in-pat-recovery.stderr | 4 ++-- 4 files changed, 31 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 9e7d4bca37d05..e8b506840ddd7 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1514,7 +1514,7 @@ impl<'a> Parser<'a> { }, ) } else if this.check_inline_const(0) { - this.parse_const_block(lo, false) + this.parse_const_block(lo) } else if this.may_recover() && this.is_do_catch_block() { this.recover_do_catch() } else if this.is_try_block() { @@ -3951,6 +3951,18 @@ impl<'a> Parser<'a> { }) } + /// Parses inline const expressions. + pub(super) fn parse_const_block(&mut self, span: Span) -> PResult<'a, Box> { + self.expect_keyword(exp!(Const))?; + let (attrs, blk) = self.parse_inner_attrs_and_block(None)?; + let anon_const = AnonConst { + id: DUMMY_NODE_ID, + value: self.mk_expr(blk.span, ExprKind::Block(blk, None)), + }; + let blk_span = anon_const.value.span; + Ok(self.mk_expr_with_attrs(span.to(blk_span), ExprKind::ConstBlock(anon_const), attrs)) + } + /// Check for `=`. This means the source incorrectly attempts to /// initialize a field with an eq rather than a colon. fn error_on_eq_field_init(&self, field_name: Ident) { diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 8577ea40589a8..98156442d492c 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1299,30 +1299,6 @@ impl<'a> Parser<'a> { } } - /// Parses inline const expressions. - fn parse_const_block(&mut self, span: Span, pat: bool) -> PResult<'a, Box> { - self.expect_keyword(exp!(Const))?; - let (attrs, blk) = self.parse_inner_attrs_and_block(None)?; - let anon_const = AnonConst { - id: DUMMY_NODE_ID, - value: self.mk_expr(blk.span, ExprKind::Block(blk, None)), - }; - let blk_span = anon_const.value.span; - let kind = if pat { - let guar = self - .dcx() - .struct_span_err(blk_span, "const blocks cannot be used as patterns") - .with_help( - "use a named `const`-item or an `if`-guard (`x if x == const { ... }`) instead", - ) - .emit(); - ExprKind::Err(guar) - } else { - ExprKind::ConstBlock(anon_const) - }; - Ok(self.mk_expr_with_attrs(span.to(blk_span), kind, attrs)) - } - /// Parses mutability (`mut` or nothing). fn parse_mutability(&mut self) -> Mutability { if self.eat_keyword(exp!(Mut)) { Mutability::Mut } else { Mutability::Not } diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 0e9796c04c8ab..f58a9dfd40e0a 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -786,7 +786,7 @@ impl<'a> Parser<'a> { self.parse_pat_box()? } else if self.check_inline_const(0) { // Parse `const pat` - let const_expr = self.parse_const_block(lo.to(self.token.span), true)?; + let const_expr = self.parse_pat_const_block(lo.to(self.token.span))?; if let Some(re) = self.parse_range_end() { self.parse_pat_range_begin_with(const_expr, re)? @@ -1281,7 +1281,7 @@ impl<'a> Parser<'a> { .then_some(self.prev_token.span); let bound = if self.check_inline_const(0) { - self.parse_const_block(self.token.span, true) + self.parse_pat_const_block(self.token.span) } else if self.check_path() { let lo = self.token.span; let (qself, path) = if self.eat_lt() { @@ -1767,6 +1767,20 @@ impl<'a> Parser<'a> { }) } + /// Parse `const {}` in patterns - this syntax has been removed, but we still parse this + /// for now to provide a more useful error. + fn parse_pat_const_block(&mut self, span: Span) -> PResult<'a, Box> { + let expr = self.parse_const_block(span)?; + let guar = self + .dcx() + .struct_span_err(expr.span, "const blocks cannot be used as patterns") + .with_help( + "use a named `const`-item or an `if`-guard (`x if x == const { ... }`) instead", + ) + .emit(); + Ok(self.mk_expr_err(expr.span, guar)) + } + pub(super) fn mk_pat_ident(&self, span: Span, ann: BindingMode, ident: Ident) -> Pat { self.mk_pat(span, PatKind::Ident(ann, ident, None)) } diff --git a/tests/ui/inline-const/in-pat-recovery.stderr b/tests/ui/inline-const/in-pat-recovery.stderr index 0698cff1480df..95c93a2a3b47f 100644 --- a/tests/ui/inline-const/in-pat-recovery.stderr +++ b/tests/ui/inline-const/in-pat-recovery.stderr @@ -1,8 +1,8 @@ error: const blocks cannot be used as patterns - --> $DIR/in-pat-recovery.rs:6:15 + --> $DIR/in-pat-recovery.rs:6:9 | LL | const { 1 + 7 } => {} - | ^^^^^^^^^ + | ^^^^^^^^^^^^^^^ | = help: use a named `const`-item or an `if`-guard (`x if x == const { ... }`) instead From 5d8c41733f8000b191d9f30f653be7f191b73bf3 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Fri, 5 Dec 2025 16:25:00 +0000 Subject: [PATCH 2/2] Remove lowering for inline const patterns This feature has been removed but some lowering remains. Let's remove them. --- compiler/rustc_ast_lowering/src/pat.rs | 1 - compiler/rustc_hir/src/hir.rs | 1 - compiler/rustc_hir/src/intravisit.rs | 1 - compiler/rustc_hir_pretty/src/lib.rs | 1 - compiler/rustc_hir_typeck/src/pat.rs | 3 -- .../rustc_mir_build/src/thir/pattern/mod.rs | 51 +------------------ compiler/rustc_parse/src/parser/mod.rs | 5 +- .../clippy/clippy_lints/src/utils/author.rs | 1 - src/tools/clippy/clippy_utils/src/consts.rs | 1 - .../clippy/clippy_utils/src/hir_utils.rs | 4 +- 10 files changed, 4 insertions(+), 65 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 3571fd6523974..e3d22a321e180 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -399,7 +399,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ExprKind::Lit(lit) => { hir::PatExprKind::Lit { lit: self.lower_lit(lit, span), negated: false } } - ExprKind::ConstBlock(c) => hir::PatExprKind::ConstBlock(self.lower_const_block(c)), ExprKind::IncludedBytes(byte_sym) => hir::PatExprKind::Lit { lit: respan(span, LitKind::ByteStr(*byte_sym, StrStyle::Cooked)), negated: false, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 6444c862d5200..8ff01746c28ca 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1926,7 +1926,6 @@ pub enum PatExprKind<'hir> { // once instead of matching on unop neg expressions everywhere. negated: bool, }, - ConstBlock(ConstBlock), /// A path pattern for a unit struct/variant or a (maybe-associated) constant. Path(QPath<'hir>), } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 625766f8bd3da..b6a0591d2c631 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -789,7 +789,6 @@ pub fn walk_pat_expr<'v, V: Visitor<'v>>(visitor: &mut V, expr: &'v PatExpr<'v>) try_visit!(visitor.visit_id(*hir_id)); match kind { PatExprKind::Lit { lit, negated } => visitor.visit_lit(*hir_id, *lit, *negated), - PatExprKind::ConstBlock(c) => visitor.visit_inline_const(c), PatExprKind::Path(qpath) => visitor.visit_qpath(qpath, *hir_id, *span), } } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index b3b416955230f..5db40615998fa 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1876,7 +1876,6 @@ impl<'a> State<'a> { } self.print_literal(lit); } - hir::PatExprKind::ConstBlock(c) => self.print_inline_const(c), hir::PatExprKind::Path(qpath) => self.print_qpath(qpath, true), } } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 0e9ff962435fc..52bb76a5550f7 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -925,9 +925,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } ty } - rustc_hir::PatExprKind::ConstBlock(c) => { - self.check_expr_const_block(c, Expectation::NoExpectation) - } rustc_hir::PatExprKind::Path(qpath) => { let (res, opt_ty, segments) = self.resolve_ty_and_res_fully_qualified_call(qpath, lt.hir_id, lt.span); diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 02e6f8d6ce717..ccd430273dd4e 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -13,14 +13,13 @@ use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::pat_util::EnumerateAndAdjustIterator; use rustc_hir::{self as hir, ByRef, LangItem, Mutability, Pinnedness, RangeEnd}; use rustc_index::Idx; -use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::interpret::LitToConstInput; use rustc_middle::thir::{ Ascription, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary, }; use rustc_middle::ty::adjustment::{PatAdjust, PatAdjustment}; use rustc_middle::ty::layout::IntegerExt; -use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, TypingMode}; +use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_span::def_id::DefId; use rustc_span::{ErrorGuaranteed, Span}; @@ -621,51 +620,6 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { pattern } - /// Lowers an inline const block (e.g. `const { 1 + 1 }`) to a pattern. - fn lower_inline_const( - &mut self, - block: &'tcx hir::ConstBlock, - id: hir::HirId, - span: Span, - ) -> PatKind<'tcx> { - let tcx = self.tcx; - let def_id = block.def_id; - let ty = tcx.typeck(def_id).node_type(block.hir_id); - - let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()); - let parent_args = ty::GenericArgs::identity_for_item(tcx, typeck_root_def_id); - let args = ty::InlineConstArgs::new(tcx, ty::InlineConstArgsParts { parent_args, ty }).args; - - let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), args }; - let c = ty::Const::new_unevaluated(self.tcx, ct); - let pattern = self.const_to_pat(c, ty, id, span); - - // Apply a type ascription for the inline constant. - let annotation = { - let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); - let args = ty::InlineConstArgs::new( - tcx, - ty::InlineConstArgsParts { parent_args, ty: infcx.next_ty_var(span) }, - ) - .args; - infcx.canonicalize_user_type_annotation(ty::UserType::new(ty::UserTypeKind::TypeOf( - def_id.to_def_id(), - ty::UserArgs { args, user_self_ty: None }, - ))) - }; - let annotation = - CanonicalUserTypeAnnotation { user_ty: Box::new(annotation), span, inferred_ty: ty }; - PatKind::AscribeUserType { - subpattern: pattern, - ascription: Ascription { - annotation, - // Note that we use `Contravariant` here. See the `variance` field documentation - // for details. - variance: ty::Contravariant, - }, - } - } - /// Lowers the kinds of "expression" that can appear in a HIR pattern: /// - Paths (e.g. `FOO`, `foo::BAR`, `Option::None`) /// - Inline const blocks (e.g. `const { 1 + 1 }`) @@ -677,9 +631,6 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { ) -> PatKind<'tcx> { match &expr.kind { hir::PatExprKind::Path(qpath) => self.lower_path(qpath, expr.hir_id, expr.span).kind, - hir::PatExprKind::ConstBlock(anon_const) => { - self.lower_inline_const(anon_const, expr.hir_id, expr.span) - } hir::PatExprKind::Lit { lit, negated } => { // We handle byte string literal patterns by using the pattern's type instead of the // literal's type in `const_to_pat`: if the literal `b"..."` matches on a slice reference, diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 98156442d492c..4058a66be6fb4 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -35,9 +35,8 @@ use rustc_ast::tokenstream::{ }; use rustc_ast::util::case::Case; use rustc_ast::{ - self as ast, AnonConst, AttrArgs, AttrId, ByRef, Const, CoroutineKind, DUMMY_NODE_ID, - DelimArgs, Expr, ExprKind, Extern, HasAttrs, HasTokens, Mutability, Recovered, Safety, StrLit, - Visibility, VisibilityKind, + self as ast, AttrArgs, AttrId, ByRef, Const, CoroutineKind, DUMMY_NODE_ID, DelimArgs, ExprKind, + Extern, HasAttrs, HasTokens, Mutability, Recovered, Safety, StrLit, Visibility, VisibilityKind, }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 03cbb0311c6ca..9a5fd125a4005 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -723,7 +723,6 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { kind!("Lit {{ ref {lit}, {negated} }}"); self.lit(lit); }, - PatExprKind::ConstBlock(_) => kind!("ConstBlock(_)"), PatExprKind::Path(_) => self.maybe_path(pat), } } diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 7e3fa4f9909b3..325fc85baa4e2 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -578,7 +578,6 @@ impl<'tcx> ConstEvalCtxt<'tcx> { Some(val) } }, - PatExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.tcx.hir_body(*body).value), PatExprKind::Path(qpath) => self.qpath(qpath, pat_expr.hir_id), } } diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index c6d82c0e63fa6..581209c68f187 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -506,9 +506,8 @@ impl HirEqInterExpr<'_, '_, '_> { negated: right_neg, }, ) => left_neg == right_neg && left.node == right.node, - (PatExprKind::ConstBlock(left), PatExprKind::ConstBlock(right)) => self.eq_body(left.body, right.body), (PatExprKind::Path(left), PatExprKind::Path(right)) => self.eq_qpath(left, right), - (PatExprKind::Lit { .. } | PatExprKind::ConstBlock(..) | PatExprKind::Path(..), _) => false, + (PatExprKind::Lit { .. } | PatExprKind::Path(..), _) => false, } } @@ -1102,7 +1101,6 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { lit.node.hash(&mut self.s); negated.hash(&mut self.s); }, - PatExprKind::ConstBlock(c) => self.hash_body(c.body), PatExprKind::Path(qpath) => self.hash_qpath(qpath), } }