about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs83
-rw-r--r--src/test/ui/inline-const/const-match-pat-generic.rs25
-rw-r--r--src/test/ui/inline-const/const-match-pat-generic.stderr20
3 files changed, 88 insertions, 40 deletions
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index ce80214c875..55cf807172e 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 4486411698a..be7e1d8d449 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<const V: usize>() {
-  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<const V: usize>() 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 a3ed41a3f6a..5fe5a7a6dad 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`.