about summary refs log tree commit diff
diff options
context:
space:
mode:
authorOli Scherer <git-spam-no-reply9815368754983@oli-obk.de>2023-02-14 09:17:34 +0000
committerOli Scherer <git-spam-no-reply9815368754983@oli-obk.de>2023-05-31 14:02:57 +0000
commitd030ece6f795c74bbb005b9a6956e5da1b9f155d (patch)
tree1ee53e257d3a80f4320a5ef2c09a83919204b7f0
parent7a2f47c271b99e30225382e53522b28dd5779103 (diff)
downloadrust-d030ece6f795c74bbb005b9a6956e5da1b9f155d.tar.gz
rust-d030ece6f795c74bbb005b9a6956e5da1b9f155d.zip
Only rewrite valtree-constants to patterns and keep other constants opaque
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs4
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs288
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs27
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs65
-rw-r--r--compiler/rustc_mir_transform/src/required_consts.rs4
-rw-r--r--tests/incremental/issue-101518.rs13
-rw-r--r--tests/mir-opt/deref-patterns/string.foo.PreCodegen.after.mir2
-rw-r--r--tests/ui/match/issue-70972-dyn-trait.rs2
-rw-r--r--tests/ui/match/issue-70972-dyn-trait.stderr2
-rw-r--r--tests/ui/pattern/issue-72565.rs2
-rw-r--r--tests/ui/pattern/issue-72565.stderr2
11 files changed, 236 insertions, 175 deletions
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 34e47de969c..72cd2218e4a 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -2487,8 +2487,8 @@ impl<'tcx> ConstantKind<'tcx> {
         if let Some(lit_input) = lit_input {
             // If an error occurred, ignore that it's a literal and leave reporting the error up to
             // mir.
-            match tcx.at(expr.span).lit_to_mir_constant(lit_input) {
-                Ok(c) => return c,
+            match tcx.at(expr.span).lit_to_const(lit_input) {
+                Ok(c) => return Self::Ty(c),
                 Err(_) => {}
             }
         }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 40298eea17c..fd4e5e4a177 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -1,13 +1,14 @@
 use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
 use rustc_index::Idx;
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::Obligation;
 use rustc_middle::mir;
 use rustc_middle::thir::{FieldPat, Pat, PatKind};
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt, ValTree};
 use rustc_session::lint;
 use rustc_span::Span;
-use rustc_target::abi::FieldIdx;
+use rustc_target::abi::{FieldIdx, VariantIdx};
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_trait_selection::traits::{self, ObligationCause};
 
@@ -29,11 +30,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         cv: mir::ConstantKind<'tcx>,
         id: hir::HirId,
         span: Span,
-        mir_structural_match_violation: bool,
+        check_body_for_struct_match_violation: Option<DefId>,
     ) -> Box<Pat<'tcx>> {
         let infcx = self.tcx.infer_ctxt().build();
         let mut convert = ConstToPat::new(self, id, span, infcx);
-        convert.to_pat(cv, mir_structural_match_violation)
+        convert.to_pat(cv, check_body_for_struct_match_violation)
     }
 }
 
@@ -104,7 +105,7 @@ impl<'tcx> ConstToPat<'tcx> {
     fn to_pat(
         &mut self,
         cv: mir::ConstantKind<'tcx>,
-        mir_structural_match_violation: bool,
+        check_body_for_struct_match_violation: Option<DefId>,
     ) -> Box<Pat<'tcx>> {
         trace!(self.treat_byte_string_as_slice);
         // This method is just a wrapper handling a validity check; the heavy lifting is
@@ -114,14 +115,44 @@ impl<'tcx> ConstToPat<'tcx> {
         // once indirect_structural_match is a full fledged error, this
         // level of indirection can be eliminated
 
-        let inlined_const_as_pat =
-            self.recur(cv, mir_structural_match_violation).unwrap_or_else(|_| {
-                Box::new(Pat {
-                    span: self.span,
-                    ty: cv.ty(),
-                    kind: PatKind::Constant { value: cv },
-                })
-            });
+        let mir_structural_match_violation = check_body_for_struct_match_violation.map(|def_id| {
+            // `mir_const_qualif` must be called with the `DefId` of the item where the const is
+            // defined, not where it is declared. The difference is significant for associated
+            // constants.
+            self.tcx().mir_const_qualif(def_id).custom_eq
+        });
+        debug!(?check_body_for_struct_match_violation, ?mir_structural_match_violation);
+
+        let inlined_const_as_pat = match cv {
+            mir::ConstantKind::Ty(c) => match c.kind() {
+                ty::ConstKind::Param(_)
+                | ty::ConstKind::Infer(_)
+                | ty::ConstKind::Bound(_, _)
+                | ty::ConstKind::Placeholder(_)
+                | ty::ConstKind::Unevaluated(_)
+                | ty::ConstKind::Error(_)
+                | ty::ConstKind::Expr(_) => {
+                    span_bug!(self.span, "unevaluated const in `to_pat`: {:?}", c.kind())
+                }
+                ty::ConstKind::Value(valtree) => self
+                    .recur(valtree, cv.ty(), mir_structural_match_violation.unwrap_or(false))
+                    .unwrap_or_else(|_| {
+                        Box::new(Pat {
+                            span: self.span,
+                            ty: cv.ty(),
+                            kind: PatKind::Constant { value: cv },
+                        })
+                    }),
+            },
+            mir::ConstantKind::Unevaluated(_, _) => {
+                span_bug!(self.span, "unevaluated const in `to_pat`: {cv:?}")
+            }
+            mir::ConstantKind::Val(_, _) => Box::new(Pat {
+                span: self.span,
+                ty: cv.ty(),
+                kind: PatKind::Constant { value: cv },
+            }),
+        };
 
         if !self.saw_const_match_error.get() {
             // If we were able to successfully convert the const to some pat,
@@ -141,29 +172,70 @@ impl<'tcx> ConstToPat<'tcx> {
             //
             // FIXME(#73448): Find a way to bring const qualification into parity with
             // `search_for_structural_match_violation`.
-            if structural.is_none() && mir_structural_match_violation {
+            if structural.is_none() && mir_structural_match_violation.unwrap_or(false) {
                 warn!("MIR const-checker found novel structural match violation. See #73448.");
                 return inlined_const_as_pat;
             }
 
             if let Some(non_sm_ty) = structural {
                 if !self.type_may_have_partial_eq_impl(cv.ty()) {
-                    // fatal avoids ICE from resolution of nonexistent method (rare case).
-                    self.tcx()
-                        .sess
-                        .emit_fatal(TypeNotStructural { span: self.span, non_sm_ty: non_sm_ty });
-                } else if mir_structural_match_violation && !self.saw_const_match_lint.get() {
-                    self.tcx().emit_spanned_lint(
-                        lint::builtin::INDIRECT_STRUCTURAL_MATCH,
-                        self.id,
-                        self.span,
-                        IndirectStructuralMatch { non_sm_ty },
-                    );
-                } else {
-                    debug!(
-                        "`search_for_structural_match_violation` found one, but `CustomEq` was \
-                          not in the qualifs for that `const`"
-                    );
+                    if let ty::Adt(def, ..) = non_sm_ty.kind() {
+                        if def.is_union() {
+                            let err = UnionPattern { span: self.span };
+                            self.tcx().sess.emit_err(err);
+                        } else {
+                            // fatal avoids ICE from resolution of nonexistent method (rare case).
+                            self.tcx()
+                                .sess
+                                .emit_fatal(TypeNotStructural { span: self.span, non_sm_ty });
+                        }
+                    } else {
+                        let err = InvalidPattern { span: self.span, non_sm_ty };
+                        self.tcx().sess.emit_err(err);
+                        return Box::new(Pat { span: self.span, ty: cv.ty(), kind: PatKind::Wild });
+                    }
+                } else if !self.saw_const_match_lint.get() {
+                    if let Some(mir_structural_match_violation) = mir_structural_match_violation {
+                        match non_sm_ty.kind() {
+                            ty::RawPtr(pointee)
+                                if pointee.ty.is_sized(self.tcx(), self.param_env) => {}
+                            ty::FnPtr(..) | ty::RawPtr(..) => {
+                                self.tcx().emit_spanned_lint(
+                                    lint::builtin::POINTER_STRUCTURAL_MATCH,
+                                    self.id,
+                                    self.span,
+                                    PointerPattern,
+                                );
+                            }
+                            ty::Adt(..) if mir_structural_match_violation => {
+                                self.tcx().emit_spanned_lint(
+                                    lint::builtin::INDIRECT_STRUCTURAL_MATCH,
+                                    self.id,
+                                    self.span,
+                                    IndirectStructuralMatch { non_sm_ty },
+                                );
+                            }
+                            _ => {
+                                debug!(
+                                    "`search_for_structural_match_violation` found one, but `CustomEq` was \
+                                  not in the qualifs for that `const`"
+                                );
+                            }
+                        }
+                    }
+                }
+            } else if !self.saw_const_match_lint.get() {
+                match cv.ty().kind() {
+                    ty::RawPtr(pointee) if pointee.ty.is_sized(self.tcx(), self.param_env) => {}
+                    ty::FnPtr(..) | ty::RawPtr(..) => {
+                        self.tcx().emit_spanned_lint(
+                            lint::builtin::POINTER_STRUCTURAL_MATCH,
+                            self.id,
+                            self.span,
+                            PointerPattern,
+                        );
+                    }
+                    _ => {}
                 }
             }
         }
@@ -171,6 +243,7 @@ impl<'tcx> ConstToPat<'tcx> {
         inlined_const_as_pat
     }
 
+    #[instrument(level = "trace", skip(self), ret)]
     fn type_may_have_partial_eq_impl(&self, ty: Ty<'tcx>) -> bool {
         // double-check there even *is* a semantic `PartialEq` to dispatch to.
         //
@@ -192,12 +265,14 @@ impl<'tcx> ConstToPat<'tcx> {
 
     fn field_pats(
         &self,
-        vals: impl Iterator<Item = mir::ConstantKind<'tcx>>,
+        vals: impl Iterator<Item = (ValTree<'tcx>, Ty<'tcx>)>,
     ) -> Result<Vec<FieldPat<'tcx>>, FallbackToConstRef> {
         vals.enumerate()
-            .map(|(idx, val)| {
+            .map(|(idx, (val, ty))| {
                 let field = FieldIdx::new(idx);
-                Ok(FieldPat { field, pattern: self.recur(val, false)? })
+                // Patterns can only use monomorphic types.
+                let ty = self.tcx().normalize_erasing_regions(self.param_env, ty);
+                Ok(FieldPat { field, pattern: self.recur(val, ty, false)? })
             })
             .collect()
     }
@@ -206,7 +281,8 @@ impl<'tcx> ConstToPat<'tcx> {
     #[instrument(skip(self), level = "debug")]
     fn recur(
         &self,
-        cv: mir::ConstantKind<'tcx>,
+        cv: ValTree<'tcx>,
+        ty: Ty<'tcx>,
         mir_structural_match_violation: bool,
     ) -> Result<Box<Pat<'tcx>>, FallbackToConstRef> {
         let id = self.id;
@@ -214,8 +290,9 @@ impl<'tcx> ConstToPat<'tcx> {
         let tcx = self.tcx();
         let param_env = self.param_env;
 
-        let kind = match cv.ty().kind() {
+        let kind = match ty.kind() {
             ty::Float(_) => {
+                self.saw_const_match_lint.set(true);
                 tcx.emit_spanned_lint(
                     lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
                     id,
@@ -224,27 +301,6 @@ impl<'tcx> ConstToPat<'tcx> {
                 );
                 return Err(FallbackToConstRef);
             }
-            ty::Adt(adt_def, _) if adt_def.is_union() => {
-                // Matching on union fields is unsafe, we can't hide it in constants
-                self.saw_const_match_error.set(true);
-                let err = UnionPattern { span };
-                tcx.sess.emit_err(err);
-                PatKind::Wild
-            }
-            ty::Adt(..)
-                if !self.type_may_have_partial_eq_impl(cv.ty())
-                    // FIXME(#73448): Find a way to bring const qualification into parity with
-                    // `search_for_structural_match_violation` and then remove this condition.
-
-                    // Obtain the actual type that isn't annotated. If we just looked at `cv.ty` we
-                    // could get `Option<NonStructEq>`, even though `Option` is annotated with derive.
-                    && let Some(non_sm_ty) = traits::search_for_structural_match_violation(span, tcx, cv.ty()) =>
-            {
-                self.saw_const_match_error.set(true);
-                let err = TypeNotStructural { span, non_sm_ty };
-                tcx.sess.emit_err(err);
-                PatKind::Wild
-            }
             // If the type is not structurally comparable, just emit the constant directly,
             // causing the pattern match code to treat it opaquely.
             // FIXME: This code doesn't emit errors itself, the caller emits the errors.
@@ -254,16 +310,14 @@ impl<'tcx> ConstToPat<'tcx> {
             // details.
             // Backwards compatibility hack because we can't cause hard errors on these
             // types, so we compare them via `PartialEq::eq` at runtime.
-            ty::Adt(..) if !self.type_marked_structural(cv.ty()) && self.behind_reference.get() => {
-                if !self.saw_const_match_error.get()
-                    && !self.saw_const_match_lint.get()
-                {
+            ty::Adt(..) if !self.type_marked_structural(ty) && self.behind_reference.get() => {
+                if !self.saw_const_match_error.get() && !self.saw_const_match_lint.get() {
                     self.saw_const_match_lint.set(true);
                     tcx.emit_spanned_lint(
                         lint::builtin::INDIRECT_STRUCTURAL_MATCH,
                         id,
                         span,
-                        IndirectStructuralMatch { non_sm_ty: cv.ty() },
+                        IndirectStructuralMatch { non_sm_ty: ty },
                     );
                 }
                 // Since we are behind a reference, we can just bubble the error up so we get a
@@ -271,39 +325,45 @@ impl<'tcx> ConstToPat<'tcx> {
                 // `PartialEq::eq` on it.
                 return Err(FallbackToConstRef);
             }
-            ty::Adt(adt_def, _) if !self.type_marked_structural(cv.ty()) => {
-                debug!(
-                    "adt_def {:?} has !type_marked_structural for cv.ty: {:?}",
-                    adt_def,
-                    cv.ty()
-                );
+            ty::Adt(adt_def, _) if !self.type_marked_structural(ty) => {
+                debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, ty,);
                 self.saw_const_match_error.set(true);
-                let err = TypeNotStructural { span, non_sm_ty: cv.ty() };
+                let err = TypeNotStructural { span, non_sm_ty: ty };
                 tcx.sess.emit_err(err);
                 PatKind::Wild
             }
             ty::Adt(adt_def, substs) if adt_def.is_enum() => {
-                let destructured = tcx.destructure_mir_constant(param_env, cv);
-
+                let (&variant_index, fields) = cv.unwrap_branch().split_first().unwrap();
+                let variant_index =
+                    VariantIdx::from_u32(variant_index.unwrap_leaf().try_to_u32().ok().unwrap());
                 PatKind::Variant {
                     adt_def: *adt_def,
                     substs,
-                    variant_index: destructured
-                        .variant
-                        .expect("destructed const of adt without variant id"),
-                    subpatterns: self.field_pats(destructured.fields.iter().copied())?,
+                    variant_index,
+                    subpatterns: self.field_pats(
+                        fields.iter().copied().zip(
+                            adt_def.variants()[variant_index]
+                                .fields
+                                .iter()
+                                .map(|field| field.ty(self.tcx(), substs)),
+                        ),
+                    )?,
                 }
             }
-            ty::Tuple(_) | ty::Adt(_, _) => {
-                let destructured = tcx.destructure_mir_constant(param_env, cv);
-                PatKind::Leaf { subpatterns: self.field_pats(destructured.fields.iter().copied())? }
-            }
-            ty::Array(..) => PatKind::Array {
-                prefix: tcx
-                    .destructure_mir_constant(param_env, cv)
-                    .fields
+            ty::Tuple(fields) => PatKind::Leaf {
+                subpatterns: self
+                    .field_pats(cv.unwrap_branch().iter().copied().zip(fields.iter()))?,
+            },
+            ty::Adt(def, substs) => PatKind::Leaf {
+                subpatterns: self.field_pats(cv.unwrap_branch().iter().copied().zip(
+                    def.non_enum_variant().fields.iter().map(|field| field.ty(self.tcx(), substs)),
+                ))?,
+            },
+            ty::Array(elem_ty, _) => PatKind::Array {
+                prefix: cv
+                    .unwrap_branch()
                     .iter()
-                    .map(|val| self.recur(*val, false))
+                    .map(|val| self.recur(*val, *elem_ty, false))
                     .collect::<Result<_, _>>()?,
                 slice: None,
                 suffix: Box::new([]),
@@ -312,36 +372,35 @@ impl<'tcx> ConstToPat<'tcx> {
                 // These are not allowed and will error elsewhere anyway.
                 ty::Dynamic(..) => {
                     self.saw_const_match_error.set(true);
-                    let err = InvalidPattern { span, non_sm_ty: cv.ty() };
+                    let err = InvalidPattern { span, non_sm_ty: ty };
                     tcx.sess.emit_err(err);
                     PatKind::Wild
                 }
-                // `&str` is represented as `ConstValue::Slice`, let's keep using this
+                // `&str` is represented as a valtree, let's keep using this
                 // optimization for now.
-                ty::Str => PatKind::Constant { value: cv },
+                ty::Str => PatKind::Constant { value: mir::ConstantKind::Ty(tcx.mk_const(cv, ty)) },
                 // `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when
                 // matching against references, you can only use byte string literals.
                 // The typechecker has a special case for byte string literals, by treating them
                 // as slices. This means we turn `&[T; N]` constants into slice patterns, which
                 // has no negative effects on pattern matching, even if we're actually matching on
                 // arrays.
-                ty::Array(..) if !self.treat_byte_string_as_slice => {
+                ty::Array(elem_ty, _) if !self.treat_byte_string_as_slice => {
                     let old = self.behind_reference.replace(true);
-                    let array = tcx.deref_mir_constant(self.param_env.and(cv));
+                    // References have the same valtree representation as their pointee.
+                    let array = cv;
                     let val = PatKind::Deref {
                         subpattern: Box::new(Pat {
                             kind: PatKind::Array {
-                                prefix: tcx
-                                    .destructure_mir_constant(param_env, array)
-                                    .fields
+                                prefix: array.unwrap_branch()
                                     .iter()
-                                    .map(|val| self.recur(*val, false))
+                                    .map(|val| self.recur(*val, elem_ty, false))
                                     .collect::<Result<_, _>>()?,
                                 slice: None,
                                 suffix: Box::new([]),
                             },
                             span,
-                            ty: *pointee_ty,
+                            ty: tcx.mk_slice(elem_ty),
                         }),
                     };
                     self.behind_reference.set(old);
@@ -353,15 +412,14 @@ impl<'tcx> ConstToPat<'tcx> {
                 // pattern.
                 ty::Slice(elem_ty) => {
                     let old = self.behind_reference.replace(true);
-                    let array = tcx.deref_mir_constant(self.param_env.and(cv));
+                    // References have the same valtree representation as their pointee.
+                    let array = cv;
                     let val = PatKind::Deref {
                         subpattern: Box::new(Pat {
                             kind: PatKind::Slice {
-                                prefix: tcx
-                                    .destructure_mir_constant(param_env, array)
-                                    .fields
+                                prefix: array.unwrap_branch()
                                     .iter()
-                                    .map(|val| self.recur(*val, false))
+                                    .map(|val| self.recur(*val, elem_ty, false))
                                     .collect::<Result<_, _>>()?,
                                 slice: None,
                                 suffix: Box::new([]),
@@ -415,39 +473,21 @@ impl<'tcx> ConstToPat<'tcx> {
                         PatKind::Wild
                     } else {
                         let old = self.behind_reference.replace(true);
-                        let subpattern = self.recur(tcx.deref_mir_constant(self.param_env.and(cv)), false)?;
+                        // References have the same valtree representation as their pointee.
+                        let subpattern = self.recur(cv, *pointee_ty, false)?;
                         self.behind_reference.set(old);
                         PatKind::Deref { subpattern }
                     }
                 }
             },
             ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::FnDef(..) => {
-                PatKind::Constant { value: cv }
-            }
-            ty::RawPtr(pointee) if pointee.ty.is_sized(tcx, param_env) => {
-                return Err(FallbackToConstRef);
-            }
-            // FIXME: these can have very surprising behaviour where optimization levels or other
-            // compilation choices change the runtime behaviour of the match.
-            // See https://github.com/rust-lang/rust/issues/70861 for examples.
-            ty::FnPtr(..) | ty::RawPtr(..) => {
-                if !self.saw_const_match_error.get()
-                    && !self.saw_const_match_lint.get()
-                {
-                    self.saw_const_match_lint.set(true);
-                    tcx.emit_spanned_lint(
-                        lint::builtin::POINTER_STRUCTURAL_MATCH,
-                        id,
-                        span,
-                        PointerPattern
-                    );
-                }
-                return Err(FallbackToConstRef);
+                PatKind::Constant { value: mir::ConstantKind::Ty(tcx.mk_const(cv, ty)) }
             }
+            ty::FnPtr(..) | ty::RawPtr(..) => unreachable!(),
             _ => {
                 self.saw_const_match_error.set(true);
-                let err = InvalidPattern { span, non_sm_ty: cv.ty() };
-                    tcx.sess.emit_err(err);
+                let err = InvalidPattern { span, non_sm_ty: ty };
+                tcx.sess.emit_err(err);
                 PatKind::Wild
             }
         };
@@ -460,7 +500,7 @@ impl<'tcx> ConstToPat<'tcx> {
 
             // Obtain the actual type that isn't annotated. If we just looked at `cv.ty` we
             // could get `Option<NonStructEq>`, even though `Option` is annotated with derive.
-            && let Some(non_sm_ty) = traits::search_for_structural_match_violation(span, tcx, cv.ty())
+            && let Some(non_sm_ty) = traits::search_for_structural_match_violation(span, tcx, ty)
         {
             self.saw_const_match_lint.set(true);
             tcx.emit_spanned_lint(
@@ -471,6 +511,6 @@ impl<'tcx> ConstToPat<'tcx> {
             );
         }
 
-        Ok(Box::new(Pat { span, ty: cv.ty(), kind }))
+        Ok(Box::new(Pat { span, ty, kind }))
     }
 }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
index 6a77146138b..6ab6fb11080 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -141,22 +141,21 @@ impl IntRange {
     ) -> Option<IntRange> {
         let ty = value.ty();
         if let Some((target_size, bias)) = Self::integral_size_and_signed_bias(tcx, ty) {
-            let val = if let mir::ConstantKind::Val(ConstValue::Scalar(scalar), _) = value {
-                // For this specific pattern we can skip a lot of effort and go
-                // straight to the result, after doing a bit of checking. (We
-                // could remove this branch and just fall through, which
-                // is more general but much slower.)
-                scalar.to_bits_or_ptr_internal(target_size).unwrap().left()?
-            } else {
-                if let mir::ConstantKind::Ty(c) = value
-                    && let ty::ConstKind::Value(_) = c.kind()
-                {
-                    bug!("encountered ConstValue in mir::ConstantKind::Ty, whereas this is expected to be in ConstantKind::Val");
+            let val = match value {
+                mir::ConstantKind::Val(ConstValue::Scalar(scalar), _) => {
+                    // For this specific pattern we can skip a lot of effort and go
+                    // straight to the result, after doing a bit of checking. (We
+                    // could remove this branch and just fall through, which
+                    // is more general but much slower.)
+                    scalar.to_bits_or_ptr_internal(target_size).unwrap().left()
                 }
-
+                mir::ConstantKind::Ty(c) if let ty::ConstKind::Value(valtree) = c.kind() => {
+                    valtree.unwrap_leaf().to_bits(target_size).ok()
+                },
                 // This is a more general form of the previous case.
-                value.try_eval_bits(tcx, param_env, ty)?
-            };
+                _ => value.try_eval_bits(tcx, param_env, ty),
+            }?;
+
             let val = val ^ bias;
             Some(IntRange { range: val..=val, bias })
         } else {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 1cf2f7ec0ff..1b4ce20004e 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -18,7 +18,7 @@ use rustc_hir::pat_util::EnumerateAndAdjustIterator;
 use rustc_hir::RangeEnd;
 use rustc_index::Idx;
 use rustc_middle::mir::interpret::{
-    ConstValue, ErrorHandled, LitToConstError, LitToConstInput, Scalar,
+    ConstValue, ErrorHandled, GlobalId, LitToConstError, LitToConstInput, Scalar,
 };
 use rustc_middle::mir::{self, UserTypeProjection};
 use rustc_middle::mir::{BorrowKind, Mutability};
@@ -518,16 +518,22 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             }
         };
 
-        // `mir_const_qualif` must be called with the `DefId` of the item where the const is
-        // defined, not where it is declared. The difference is significant for associated
-        // constants.
-        let mir_structural_match_violation = self.tcx.mir_const_qualif(instance.def_id()).custom_eq;
-        debug!("mir_structural_match_violation({:?}) -> {}", qpath, mir_structural_match_violation);
-
-        match self.tcx.const_eval_instance(param_env_reveal_all, instance, Some(span)) {
-            Ok(literal) => {
-                let const_ = mir::ConstantKind::Val(literal, ty);
-                let pattern = self.const_to_pat(const_, id, span, mir_structural_match_violation);
+        let cid = GlobalId { instance, promoted: None };
+        // Prefer
+        let const_value = self
+            .tcx
+            .const_eval_global_id_for_typeck(param_env_reveal_all, cid, Some(span))
+            .and_then(|val| match val {
+                Some(valtree) => Ok(mir::ConstantKind::Ty(self.tcx.mk_const(valtree, ty))),
+                None => self
+                    .tcx
+                    .const_eval_global_id(param_env_reveal_all, cid, Some(span))
+                    .map(|lit| mir::ConstantKind::Val(lit, ty)),
+            });
+
+        match const_value {
+            Ok(const_) => {
+                let pattern = self.const_to_pat(const_, id, span, Some(instance.def_id()));
 
                 if !is_associated_const {
                     return pattern;
@@ -578,9 +584,21 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         span: Span,
     ) -> PatKind<'tcx> {
         let value = mir::ConstantKind::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);
+        let value = match value {
+            mir::ConstantKind::Ty(_) => value,
+            // Evaluate early like we do in `lower_path`.
+            mir::ConstantKind::Unevaluated(ct, ty) => {
+                let ct = ty::UnevaluatedConst { def: ct.def, substs: ct.substs };
+                if let Ok(Some(valtree)) =
+                    self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, Some(span))
+                {
+                    mir::ConstantKind::Ty(self.tcx.mk_const(valtree, ty))
+                } else {
+                    value.eval(self.tcx, self.param_env)
+                }
+            }
+            mir::ConstantKind::Val(_, _) => unreachable!(),
+        };
 
         match value {
             mir::ConstantKind::Ty(c) => match c.kind() {
@@ -591,15 +609,17 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                 ConstKind::Error(_) => {
                     return PatKind::Wild;
                 }
-                _ => bug!("Expected ConstKind::Param"),
+                _ => {}
             },
-            mir::ConstantKind::Val(_, _) => self.const_to_pat(value, id, span, false).kind,
+            mir::ConstantKind::Val(_, _) => {}
             mir::ConstantKind::Unevaluated(..) => {
                 // If we land here it means the const can't be evaluated because it's `TooGeneric`.
                 self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
                 return PatKind::Wild;
             }
         }
+
+        self.const_to_pat(value, id, span, None).kind
     }
 
     /// Converts literals, paths and negation of literals to patterns.
@@ -626,8 +646,14 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
 
         let lit_input =
             LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg };
-        match self.tcx.at(expr.span).lit_to_mir_constant(lit_input) {
-            Ok(constant) => self.const_to_pat(constant, expr.hir_id, lit.span, false).kind,
+        match self
+            .tcx
+            .at(expr.span)
+            .lit_to_const(lit_input)
+            .map(mir::ConstantKind::Ty)
+            .or_else(|_| self.tcx.at(expr.span).lit_to_mir_constant(lit_input))
+        {
+            Ok(constant) => self.const_to_pat(constant, expr.hir_id, lit.span, None).kind,
             Err(LitToConstError::Reported(_)) => PatKind::Wild,
             Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"),
         }
@@ -806,6 +832,9 @@ pub(crate) fn compare_const_vals<'tcx>(
                 mir::ConstantKind::Val(ConstValue::Scalar(Scalar::Int(a)), _a_ty),
                 mir::ConstantKind::Val(ConstValue::Scalar(Scalar::Int(b)), _b_ty),
             ) => return Some(a.cmp(&b)),
+            (mir::ConstantKind::Ty(a), mir::ConstantKind::Ty(b)) => {
+                return Some(a.kind().cmp(&b.kind()));
+            }
             _ => {}
         },
     }
diff --git a/compiler/rustc_mir_transform/src/required_consts.rs b/compiler/rustc_mir_transform/src/required_consts.rs
index 0ea8f2ba93f..243cb463560 100644
--- a/compiler/rustc_mir_transform/src/required_consts.rs
+++ b/compiler/rustc_mir_transform/src/required_consts.rs
@@ -17,8 +17,8 @@ impl<'tcx> Visitor<'tcx> for RequiredConstsVisitor<'_, 'tcx> {
         let literal = constant.literal;
         match literal {
             ConstantKind::Ty(c) => match c.kind() {
-                ConstKind::Param(_) | ConstKind::Error(_) => {}
-                _ => bug!("only ConstKind::Param should be encountered here, got {:#?}", c),
+                ConstKind::Param(_) | ConstKind::Error(_) | ConstKind::Value(_) => {}
+                _ => bug!("only ConstKind::Param/Value should be encountered here, got {:#?}", c),
             },
             ConstantKind::Unevaluated(..) => self.required_consts.push(*constant),
             ConstantKind::Val(..) => {}
diff --git a/tests/incremental/issue-101518.rs b/tests/incremental/issue-101518.rs
index 501be175fce..39373da6a9f 100644
--- a/tests/incremental/issue-101518.rs
+++ b/tests/incremental/issue-101518.rs
@@ -1,7 +1,4 @@
-// revisions: cfail1
-// should-ice
-// error-pattern: forcing query
-// known-bug: #101518
+// revisions: cpass
 
 #[derive(PartialEq, Eq)]
 struct Id<'a> {
@@ -9,9 +6,7 @@ struct Id<'a> {
 }
 fn visit_struct() {
     let id = Id { ns: "random1" };
-    const FLAG: Id<'static> = Id {
-        ns: "needs_to_be_the_same",
-    };
+    const FLAG: Id<'static> = Id { ns: "needs_to_be_the_same" };
     match id {
         FLAG => {}
         _ => {}
@@ -19,9 +14,7 @@ fn visit_struct() {
 }
 fn visit_struct2() {
     let id = Id { ns: "random2" };
-    const FLAG: Id<'static> = Id {
-        ns: "needs_to_be_the_same",
-    };
+    const FLAG: Id<'static> = Id { ns: "needs_to_be_the_same" };
     match id {
         FLAG => {}
         _ => {}
diff --git a/tests/mir-opt/deref-patterns/string.foo.PreCodegen.after.mir b/tests/mir-opt/deref-patterns/string.foo.PreCodegen.after.mir
index bcdb12011bc..61ce5e54fdc 100644
--- a/tests/mir-opt/deref-patterns/string.foo.PreCodegen.after.mir
+++ b/tests/mir-opt/deref-patterns/string.foo.PreCodegen.after.mir
@@ -35,7 +35,7 @@ fn foo(_1: Option<String>) -> i32 {
                                          // + literal: Const { ty: for<'a, 'b> fn(&'a str, &'b str) -> bool {<str as PartialEq>::eq}, val: Value(<ZST>) }
                                          // mir::Constant
                                          // + span: $DIR/string.rs:9:14: 9:17
-                                         // + literal: Const { ty: &str, val: Value(Slice(..)) }
+                                         // + literal: Const { ty: &str, val: Value(ValTree::Branch(..)) }
     }
 
     bb3: {
diff --git a/tests/ui/match/issue-70972-dyn-trait.rs b/tests/ui/match/issue-70972-dyn-trait.rs
index 97d161c59ec..df28c474ab0 100644
--- a/tests/ui/match/issue-70972-dyn-trait.rs
+++ b/tests/ui/match/issue-70972-dyn-trait.rs
@@ -4,7 +4,7 @@ fn main() {
     let a: &dyn Send = &7u32;
     match a {
         F => panic!(),
-        //~^ ERROR `&dyn Send` cannot be used in patterns
+        //~^ ERROR `dyn Send` cannot be used in patterns
         _ => {}
     }
 }
diff --git a/tests/ui/match/issue-70972-dyn-trait.stderr b/tests/ui/match/issue-70972-dyn-trait.stderr
index 7581070ebc1..f4dc910c34a 100644
--- a/tests/ui/match/issue-70972-dyn-trait.stderr
+++ b/tests/ui/match/issue-70972-dyn-trait.stderr
@@ -1,4 +1,4 @@
-error: `&dyn Send` cannot be used in patterns
+error: `dyn Send` cannot be used in patterns
   --> $DIR/issue-70972-dyn-trait.rs:6:9
    |
 LL |         F => panic!(),
diff --git a/tests/ui/pattern/issue-72565.rs b/tests/ui/pattern/issue-72565.rs
index 1e262fd5067..21edb26de08 100644
--- a/tests/ui/pattern/issue-72565.rs
+++ b/tests/ui/pattern/issue-72565.rs
@@ -3,6 +3,6 @@ const F: &'static dyn PartialEq<u32> = &7u32;
 fn main() {
     let a: &dyn PartialEq<u32> = &7u32;
     match a {
-        F => panic!(), //~ ERROR: `&dyn PartialEq<u32>` cannot be used in patterns
+        F => panic!(), //~ ERROR: `dyn PartialEq<u32>` cannot be used in patterns
     }
 }
diff --git a/tests/ui/pattern/issue-72565.stderr b/tests/ui/pattern/issue-72565.stderr
index 2f82616b277..0519720694d 100644
--- a/tests/ui/pattern/issue-72565.stderr
+++ b/tests/ui/pattern/issue-72565.stderr
@@ -1,4 +1,4 @@
-error: `&dyn PartialEq<u32>` cannot be used in patterns
+error: `dyn PartialEq<u32>` cannot be used in patterns
   --> $DIR/issue-72565.rs:6:9
    |
 LL |         F => panic!(),