diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index ce80214c875fc..55cf807172e02 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -533,43 +533,64 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } } + /// Converts inline const patterns. + fn lower_inline_const( + &mut self, + anon_const: &'tcx hir::AnonConst, + id: hir::HirId, + span: Span, + ) -> PatKind<'tcx> { + let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id); + let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id); + + // Evaluate early like we do in `lower_path`. + let value = value.eval(self.tcx, self.param_env); + + match value.val { + ConstKind::Param(_) => { + self.errors.push(PatternError::ConstParamInPattern(span)); + return PatKind::Wild; + } + ConstKind::Unevaluated(_) => { + // If we land here it means the const can't be evaluated because it's `TooGeneric`. + self.tcx.sess.span_err(span, "constant pattern depends on a generic parameter"); + return PatKind::Wild; + } + _ => (), + } + + *self.const_to_pat(value, id, span, false).kind + } + /// Converts literals, paths and negation of literals to patterns. /// The special case for negation exists to allow things like `-128_i8` /// which would overflow if we tried to evaluate `128_i8` and then negate /// afterwards. fn lower_lit(&mut self, expr: &'tcx hir::Expr<'tcx>) -> PatKind<'tcx> { - if let hir::ExprKind::Path(ref qpath) = expr.kind { - *self.lower_path(qpath, expr.hir_id, expr.span).kind - } else { - let (lit, neg) = match expr.kind { - hir::ExprKind::ConstBlock(ref anon_const) => { - let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id); - let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id); - if matches!(value.val, ConstKind::Param(_)) { - let span = self.tcx.hir().span(anon_const.hir_id); - self.errors.push(PatternError::ConstParamInPattern(span)); - return PatKind::Wild; - } - return *self.const_to_pat(value, expr.hir_id, expr.span, false).kind; - } - hir::ExprKind::Lit(ref lit) => (lit, false), - hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => { - let lit = match expr.kind { - hir::ExprKind::Lit(ref lit) => lit, - _ => span_bug!(expr.span, "not a literal: {:?}", expr), - }; - (lit, true) - } - _ => span_bug!(expr.span, "not a literal: {:?}", expr), - }; - - let lit_input = - LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg }; - match self.tcx.at(expr.span).lit_to_const(lit_input) { - Ok(val) => *self.const_to_pat(val, expr.hir_id, lit.span, false).kind, - Err(LitToConstError::Reported) => PatKind::Wild, - Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"), + let (lit, neg) = match expr.kind { + hir::ExprKind::Path(ref qpath) => { + return *self.lower_path(qpath, expr.hir_id, expr.span).kind; + } + hir::ExprKind::ConstBlock(ref anon_const) => { + return self.lower_inline_const(anon_const, expr.hir_id, expr.span); + } + hir::ExprKind::Lit(ref lit) => (lit, false), + hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => { + let lit = match expr.kind { + hir::ExprKind::Lit(ref lit) => lit, + _ => span_bug!(expr.span, "not a literal: {:?}", expr), + }; + (lit, true) } + _ => span_bug!(expr.span, "not a literal: {:?}", expr), + }; + + let lit_input = + LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg }; + match self.tcx.at(expr.span).lit_to_const(lit_input) { + Ok(val) => *self.const_to_pat(val, expr.hir_id, lit.span, false).kind, + Err(LitToConstError::Reported) => PatKind::Wild, + Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"), } } } diff --git a/src/test/ui/inline-const/const-match-pat-generic.rs b/src/test/ui/inline-const/const-match-pat-generic.rs index 4486411698af9..be7e1d8d44984 100644 --- a/src/test/ui/inline-const/const-match-pat-generic.rs +++ b/src/test/ui/inline-const/const-match-pat-generic.rs @@ -1,16 +1,31 @@ #![allow(incomplete_features)] #![feature(inline_const_pat)] +#![feature(generic_const_exprs)] // rust-lang/rust#82518: ICE with inline-const in match referencing const-generic parameter fn foo() { - match 0 { - const { V } => {}, - //~^ ERROR const parameters cannot be referenced in patterns [E0158] - _ => {}, - } + match 0 { + const { V } => {}, + //~^ ERROR const parameters cannot be referenced in patterns [E0158] + _ => {}, + } +} + +const fn f(x: usize) -> usize { + x + 1 +} + +fn bar() where [(); f(V)]: { + match 0 { + const { f(V) } => {}, + //~^ ERROR constant pattern depends on a generic parameter + //~| ERROR constant pattern depends on a generic parameter + _ => {}, + } } fn main() { foo::<1>(); + bar::<1>(); } diff --git a/src/test/ui/inline-const/const-match-pat-generic.stderr b/src/test/ui/inline-const/const-match-pat-generic.stderr index a3ed41a3f6af8..5fe5a7a6dad41 100644 --- a/src/test/ui/inline-const/const-match-pat-generic.stderr +++ b/src/test/ui/inline-const/const-match-pat-generic.stderr @@ -1,9 +1,21 @@ error[E0158]: const parameters cannot be referenced in patterns - --> $DIR/const-match-pat-generic.rs:8:11 + --> $DIR/const-match-pat-generic.rs:9:9 | -LL | const { V } => {}, - | ^^^^^ +LL | const { V } => {}, + | ^^^^^^^^^^^ -error: aborting due to previous error +error: constant pattern depends on a generic parameter + --> $DIR/const-match-pat-generic.rs:21:9 + | +LL | const { f(V) } => {}, + | ^^^^^^^^^^^^^^ + +error: constant pattern depends on a generic parameter + --> $DIR/const-match-pat-generic.rs:21:9 + | +LL | const { f(V) } => {}, + | ^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0158`.