diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index 370b15d2871a9..8c7acf18ec428 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -6,6 +6,7 @@ ast_lowering_abi_specified_multiple_times = ast_lowering_arbitrary_expression_in_pattern = arbitrary expressions aren't allowed in patterns .pattern_from_macro_note = the `expr` fragment specifier forces the metavariable's content to be an expression + .const_block_in_pattern_help = use a named `const`-item or an `if`-guard (`x if x == const {"{ ... }"}`) instead ast_lowering_argument = argument diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 83f3a976e83f7..79e2d74a8b5ab 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -357,6 +357,8 @@ pub(crate) struct ArbitraryExpressionInPattern { pub span: Span, #[note(ast_lowering_pattern_from_macro_note)] pub pattern_from_macro_note: bool, + #[help(ast_lowering_const_block_in_pattern_help)] + pub const_block_in_pattern_help: bool, } #[derive(Diagnostic)] diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 3571fd6523974..7a5d8d9847a1f 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, @@ -419,10 +418,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::PatExprKind::Lit { lit: self.lower_lit(lit, span), negated: true } } _ => { + let is_const_block = matches!(expr.kind, ExprKind::ConstBlock(_)); let pattern_from_macro = expr.is_approximately_pattern(); let guar = self.dcx().emit_err(ArbitraryExpressionInPattern { span, pattern_from_macro_note: pattern_from_macro, + const_block_in_pattern_help: is_const_block, }); err(guar) } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 77e86fdce38d1..e5a646e3116dd 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1921,7 +1921,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/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 9e7d4bca37d05..a5f8145bee8f1 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() { diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 8577ea40589a8..97cb77ab13d2c 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1300,7 +1300,7 @@ impl<'a> Parser<'a> { } /// Parses inline const expressions. - fn parse_const_block(&mut self, span: Span, pat: bool) -> PResult<'a, Box> { + 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 { @@ -1308,18 +1308,7 @@ impl<'a> Parser<'a> { 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) - }; + let kind = ExprKind::ConstBlock(anon_const); Ok(self.mk_expr_with_attrs(span.to(blk_span), kind, attrs)) } diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 0e9796c04c8ab..d7f3a36122e59 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -785,8 +785,10 @@ impl<'a> Parser<'a> { } else if self.eat_keyword(exp!(Box)) { 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)?; + // Parse `const pat`. + // NOTE: This will always error later during AST lowering because + // inline const cannot be used as patterns. + let const_expr = self.parse_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 +1283,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_const_block(self.token.span) } else if self.check_path() { let lo = self.token.span; let (qself, path) = if self.eat_lt() { 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), } } diff --git a/tests/ui/inline-const/in-pat-recovery.rs b/tests/ui/inline-const/in-pat-recovery.rs index a46e56e3be649..d519217fad3b5 100644 --- a/tests/ui/inline-const/in-pat-recovery.rs +++ b/tests/ui/inline-const/in-pat-recovery.rs @@ -4,8 +4,63 @@ fn main() { match 1 { const { 1 + 7 } => {} - //~^ ERROR const blocks cannot be used as patterns + //~^ ERROR arbitrary expressions aren't allowed in patterns 2 => {} _ => {} } + + match 5 { + const { 1 } ..= 10 => {} + //~^ ERROR arbitrary expressions aren't allowed in patterns + _ => {} + } + + match 5 { + 1 ..= const { 10 } => {} + //~^ ERROR arbitrary expressions aren't allowed in patterns + _ => {} + } + + match 5 { + const { 1 } ..= const { 10 } => {} + //~^ ERROR arbitrary expressions aren't allowed in patterns + //~| ERROR arbitrary expressions aren't allowed in patterns + _ => {} + } + + match 5 { + const { 1 } .. 10 => {} + //~^ ERROR arbitrary expressions aren't allowed in patterns + _ => {} + } + + match 5 { + 1 .. const { 10 } => {} + //~^ ERROR arbitrary expressions aren't allowed in patterns + _ => {} + } + + match 5 { + const { 1 + 2 } ..= 10 => {} + //~^ ERROR arbitrary expressions aren't allowed in patterns + _ => {} + } + + match 5 { + 1 ..= const { 5 + 5 } => {} + //~^ ERROR arbitrary expressions aren't allowed in patterns + _ => {} + } + + match 5 { + const { 3 } .. => {} + //~^ ERROR arbitrary expressions aren't allowed in patterns + _ => {} + } + + match 5 { + ..= const { 7 } => {} + //~^ ERROR arbitrary expressions aren't allowed in patterns + _ => {} + } } diff --git a/tests/ui/inline-const/in-pat-recovery.stderr b/tests/ui/inline-const/in-pat-recovery.stderr index 0698cff1480df..376c43aaecca6 100644 --- a/tests/ui/inline-const/in-pat-recovery.stderr +++ b/tests/ui/inline-const/in-pat-recovery.stderr @@ -1,10 +1,90 @@ -error: const blocks cannot be used as patterns - --> $DIR/in-pat-recovery.rs:6:15 +error: arbitrary expressions aren't allowed in patterns + --> $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 -error: aborting due to 1 previous error +error: arbitrary expressions aren't allowed in patterns + --> $DIR/in-pat-recovery.rs:13:9 + | +LL | const { 1 } ..= 10 => {} + | ^^^^^^^^^^^ + | + = help: use a named `const`-item or an `if`-guard (`x if x == const { ... }`) instead + +error: arbitrary expressions aren't allowed in patterns + --> $DIR/in-pat-recovery.rs:19:15 + | +LL | 1 ..= const { 10 } => {} + | ^^^^^^^^^^^^ + | + = help: use a named `const`-item or an `if`-guard (`x if x == const { ... }`) instead + +error: arbitrary expressions aren't allowed in patterns + --> $DIR/in-pat-recovery.rs:25:9 + | +LL | const { 1 } ..= const { 10 } => {} + | ^^^^^^^^^^^ + | + = help: use a named `const`-item or an `if`-guard (`x if x == const { ... }`) instead + +error: arbitrary expressions aren't allowed in patterns + --> $DIR/in-pat-recovery.rs:25:25 + | +LL | const { 1 } ..= const { 10 } => {} + | ^^^^^^^^^^^^ + | + = help: use a named `const`-item or an `if`-guard (`x if x == const { ... }`) instead + +error: arbitrary expressions aren't allowed in patterns + --> $DIR/in-pat-recovery.rs:32:9 + | +LL | const { 1 } .. 10 => {} + | ^^^^^^^^^^^ + | + = help: use a named `const`-item or an `if`-guard (`x if x == const { ... }`) instead + +error: arbitrary expressions aren't allowed in patterns + --> $DIR/in-pat-recovery.rs:38:14 + | +LL | 1 .. const { 10 } => {} + | ^^^^^^^^^^^^ + | + = help: use a named `const`-item or an `if`-guard (`x if x == const { ... }`) instead + +error: arbitrary expressions aren't allowed in patterns + --> $DIR/in-pat-recovery.rs:44:9 + | +LL | const { 1 + 2 } ..= 10 => {} + | ^^^^^^^^^^^^^^^ + | + = help: use a named `const`-item or an `if`-guard (`x if x == const { ... }`) instead + +error: arbitrary expressions aren't allowed in patterns + --> $DIR/in-pat-recovery.rs:50:15 + | +LL | 1 ..= const { 5 + 5 } => {} + | ^^^^^^^^^^^^^^^ + | + = help: use a named `const`-item or an `if`-guard (`x if x == const { ... }`) instead + +error: arbitrary expressions aren't allowed in patterns + --> $DIR/in-pat-recovery.rs:56:9 + | +LL | const { 3 } .. => {} + | ^^^^^^^^^^^ + | + = help: use a named `const`-item or an `if`-guard (`x if x == const { ... }`) instead + +error: arbitrary expressions aren't allowed in patterns + --> $DIR/in-pat-recovery.rs:62:13 + | +LL | ..= const { 7 } => {} + | ^^^^^^^^^^^ + | + = help: use a named `const`-item or an `if`-guard (`x if x == const { ... }`) instead + +error: aborting due to 11 previous errors diff --git a/tests/ui/pattern/deref-patterns/ice-adjust-mode-unimplemented-for-constblock.rs b/tests/ui/pattern/deref-patterns/ice-adjust-mode-unimplemented-for-constblock.rs new file mode 100644 index 0000000000000..fac8684ef094d --- /dev/null +++ b/tests/ui/pattern/deref-patterns/ice-adjust-mode-unimplemented-for-constblock.rs @@ -0,0 +1,10 @@ +#![feature(deref_patterns)] +#![expect(incomplete_features)] + +fn main() { + let vec![const { vec![] }]: Vec = vec![]; + //~^ ERROR expected a pattern, found a function call + //~| ERROR usage of qualified paths in this context is experimental + //~| ERROR expected tuple struct or tuple variant + //~| ERROR arbitrary expressions aren't allowed in patterns +} diff --git a/tests/ui/pattern/deref-patterns/ice-adjust-mode-unimplemented-for-constblock.stderr b/tests/ui/pattern/deref-patterns/ice-adjust-mode-unimplemented-for-constblock.stderr new file mode 100644 index 0000000000000..43b0ad18a79b7 --- /dev/null +++ b/tests/ui/pattern/deref-patterns/ice-adjust-mode-unimplemented-for-constblock.stderr @@ -0,0 +1,41 @@ +error[E0532]: expected a pattern, found a function call + --> $DIR/ice-adjust-mode-unimplemented-for-constblock.rs:5:9 + | +LL | let vec![const { vec![] }]: Vec = vec![]; + | ^^^^^^^^^^^^^^^^^^^^^^ not a tuple struct or tuple variant + | + = note: function calls are not allowed in patterns: + = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0658]: usage of qualified paths in this context is experimental + --> $DIR/ice-adjust-mode-unimplemented-for-constblock.rs:5:9 + | +LL | let vec![const { vec![] }]: Vec = vec![]; + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #86935 for more information + = help: add `#![feature(more_qualified_paths)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: arbitrary expressions aren't allowed in patterns + --> $DIR/ice-adjust-mode-unimplemented-for-constblock.rs:5:14 + | +LL | let vec![const { vec![] }]: Vec = vec![]; + | ^^^^^^^^^^^^^^^^ + | + = help: use a named `const`-item or an `if`-guard (`x if x == const { ... }`) instead + +error[E0164]: expected tuple struct or tuple variant, found associated function `<[_]>::into_vec` + --> $DIR/ice-adjust-mode-unimplemented-for-constblock.rs:5:9 + | +LL | let vec![const { vec![] }]: Vec = vec![]; + | ^^^^^^^^^^^^^^^^^^^^^^ `fn` calls are not allowed in patterns + | + = help: for more information, visit https://doc.rust-lang.org/book/ch19-00-patterns.html + = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0164, E0532, E0658. +For more information about an error, try `rustc --explain E0164`.