summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs')
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs190
1 files changed, 52 insertions, 138 deletions
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 a21f6cd39..7f3519945 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,11 +1,9 @@
-use rustc_errors::DelayDm;
use rustc_hir as hir;
use rustc_index::vec::Idx;
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_middle::mir::{self, Field};
use rustc_middle::thir::{FieldPat, Pat, PatKind};
-use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::lint;
use rustc_span::Span;
use rustc_trait_selection::traits::predicate_for_trait_def;
@@ -15,6 +13,10 @@ use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligation};
use std::cell::Cell;
use super::PatCtxt;
+use crate::errors::{
+ FloatPattern, IndirectStructuralMatch, InvalidPattern, NontrivialStructuralMatch,
+ PointerPattern, TypeNotStructural, UnionPattern, UnsizedPattern,
+};
impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
/// Converts an evaluated constant to a pattern (if possible).
@@ -70,7 +72,7 @@ mod fallback_to_const_ref {
/// hoops to get a reference to the value.
pub(super) struct FallbackToConstRef(());
- pub(super) fn fallback_to_const_ref<'tcx>(c2p: &super::ConstToPat<'tcx>) -> FallbackToConstRef {
+ pub(super) fn fallback_to_const_ref(c2p: &super::ConstToPat<'_>) -> FallbackToConstRef {
assert!(c2p.behind_reference.get());
FallbackToConstRef(())
}
@@ -105,47 +107,6 @@ impl<'tcx> ConstToPat<'tcx> {
self.infcx.tcx
}
- fn adt_derive_msg(&self, adt_def: AdtDef<'tcx>) -> String {
- let path = self.tcx().def_path_str(adt_def.did());
- format!(
- "to use a constant of type `{}` in a pattern, \
- `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
- path, path,
- )
- }
-
- fn search_for_structural_match_violation(&self, ty: Ty<'tcx>) -> Option<String> {
- traits::search_for_structural_match_violation(self.span, self.tcx(), ty).map(|non_sm_ty| {
- with_no_trimmed_paths!(match non_sm_ty.kind() {
- ty::Adt(adt, _) => self.adt_derive_msg(*adt),
- ty::Dynamic(..) => {
- "trait objects cannot be used in patterns".to_string()
- }
- ty::Opaque(..) => {
- "opaque types cannot be used in patterns".to_string()
- }
- ty::Closure(..) => {
- "closures cannot be used in patterns".to_string()
- }
- ty::Generator(..) | ty::GeneratorWitness(..) => {
- "generators cannot be used in patterns".to_string()
- }
- ty::Float(..) => {
- "floating-point numbers cannot be used in patterns".to_string()
- }
- ty::FnPtr(..) => {
- "function pointers cannot be used in patterns".to_string()
- }
- ty::RawPtr(..) => {
- "raw pointers cannot be used in patterns".to_string()
- }
- _ => {
- bug!("use of a value of `{non_sm_ty}` inside a pattern")
- }
- })
- })
- }
-
fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool {
ty.is_structural_eq_shallow(self.infcx.tcx)
}
@@ -176,7 +137,8 @@ impl<'tcx> ConstToPat<'tcx> {
// If we were able to successfully convert the const to some pat,
// double-check that all types in the const implement `Structural`.
- let structural = self.search_for_structural_match_violation(cv.ty());
+ let structural =
+ traits::search_for_structural_match_violation(self.span, self.tcx(), cv.ty());
debug!(
"search_for_structural_match_violation cv.ty: {:?} returned: {:?}",
cv.ty(),
@@ -194,17 +156,18 @@ impl<'tcx> ConstToPat<'tcx> {
return inlined_const_as_pat;
}
- if let Some(msg) = structural {
+ if let Some(non_sm_ty) = structural {
if !self.type_may_have_partial_eq_impl(cv.ty()) {
- // span_fatal avoids ICE from resolution of non-existent method (rare case).
- self.tcx().sess.span_fatal(self.span, &msg);
+ // fatal avoids ICE from resolution of non-existent 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().struct_span_lint_hir(
+ self.tcx().emit_spanned_lint(
lint::builtin::INDIRECT_STRUCTURAL_MATCH,
self.id,
self.span,
- msg,
- |lint| lint,
+ IndirectStructuralMatch { non_sm_ty },
);
} else {
debug!(
@@ -278,12 +241,11 @@ impl<'tcx> ConstToPat<'tcx> {
let kind = match cv.ty().kind() {
ty::Float(_) => {
if self.include_lint_checks {
- tcx.struct_span_lint_hir(
+ tcx.emit_spanned_lint(
lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
id,
span,
- "floating-point types cannot be used in patterns",
- |lint| lint,
+ FloatPattern,
);
}
PatKind::Constant { value: cv }
@@ -291,29 +253,22 @@ impl<'tcx> ConstToPat<'tcx> {
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 msg = "cannot use unions in constant patterns";
- if self.include_lint_checks {
- tcx.sess.span_err(span, msg);
- } else {
- tcx.sess.delay_span_bug(span, msg);
- }
+ let err = UnionPattern { span };
+ tcx.sess.create_err(err).emit_unless(!self.include_lint_checks);
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.
- && self.search_for_structural_match_violation(cv.ty()).is_some() =>
+
+ // 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()) =>
{
- // 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 msg = self.search_for_structural_match_violation(cv.ty()).unwrap();
self.saw_const_match_error.set(true);
- if self.include_lint_checks {
- tcx.sess.span_err(self.span, &msg);
- } else {
- tcx.sess.delay_span_bug(self.span, &msg);
- }
+ let err = TypeNotStructural { span, non_sm_ty };
+ tcx.sess.create_err(err).emit_unless(!self.include_lint_checks);
PatKind::Wild
}
// If the type is not structurally comparable, just emit the constant directly,
@@ -331,19 +286,11 @@ impl<'tcx> ConstToPat<'tcx> {
&& !self.saw_const_match_lint.get()
{
self.saw_const_match_lint.set(true);
- tcx.struct_span_lint_hir(
+ tcx.emit_spanned_lint(
lint::builtin::INDIRECT_STRUCTURAL_MATCH,
id,
span,
- DelayDm(|| {
- format!(
- "to use a constant of type `{}` in a pattern, \
- `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
- cv.ty(),
- cv.ty(),
- )
- }),
- |lint| lint,
+ IndirectStructuralMatch { non_sm_ty: cv.ty() },
);
}
// Since we are behind a reference, we can just bubble the error up so we get a
@@ -357,18 +304,9 @@ impl<'tcx> ConstToPat<'tcx> {
adt_def,
cv.ty()
);
- let path = tcx.def_path_str(adt_def.did());
- let msg = format!(
- "to use a constant of type `{}` in a pattern, \
- `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
- path, path,
- );
self.saw_const_match_error.set(true);
- if self.include_lint_checks {
- tcx.sess.span_err(span, &msg);
- } else {
- tcx.sess.delay_span_bug(span, &msg);
- }
+ let err = TypeNotStructural { span, non_sm_ty: cv.ty() };
+ tcx.sess.create_err(err).emit_unless(!self.include_lint_checks);
PatKind::Wild
}
ty::Adt(adt_def, substs) if adt_def.is_enum() => {
@@ -401,12 +339,8 @@ impl<'tcx> ConstToPat<'tcx> {
// These are not allowed and will error elsewhere anyway.
ty::Dynamic(..) => {
self.saw_const_match_error.set(true);
- let msg = format!("`{}` cannot be used in patterns", cv.ty());
- if self.include_lint_checks {
- tcx.sess.span_err(span, &msg);
- } else {
- tcx.sess.delay_span_bug(span, &msg);
- }
+ let err = InvalidPattern { span, non_sm_ty: cv.ty() };
+ tcx.sess.create_err(err).emit_unless(!self.include_lint_checks);
PatKind::Wild
}
// `&str` is represented as `ConstValue::Slice`, let's keep using this
@@ -471,32 +405,26 @@ impl<'tcx> ConstToPat<'tcx> {
// this pattern to a `PartialEq::eq` comparison and `PartialEq::eq` takes a
// reference. This makes the rest of the matching logic simpler as it doesn't have
// to figure out how to get a reference again.
- ty::Adt(adt_def, _) if !self.type_marked_structural(*pointee_ty) => {
+ ty::Adt(_, _) if !self.type_marked_structural(*pointee_ty) => {
if self.behind_reference.get() {
if self.include_lint_checks
&& !self.saw_const_match_error.get()
&& !self.saw_const_match_lint.get()
{
- self.saw_const_match_lint.set(true);
- let msg = self.adt_derive_msg(adt_def);
- self.tcx().struct_span_lint_hir(
+ self.saw_const_match_lint.set(true);
+ tcx.emit_spanned_lint(
lint::builtin::INDIRECT_STRUCTURAL_MATCH,
self.id,
- self.span,
- msg,
- |lint| lint,
+ span,
+ IndirectStructuralMatch { non_sm_ty: *pointee_ty },
);
}
PatKind::Constant { value: cv }
} else {
if !self.saw_const_match_error.get() {
self.saw_const_match_error.set(true);
- let msg = self.adt_derive_msg(adt_def);
- if self.include_lint_checks {
- tcx.sess.span_err(span, &msg);
- } else {
- tcx.sess.delay_span_bug(span, &msg);
- }
+ let err = TypeNotStructural { span, non_sm_ty: *pointee_ty };
+ tcx.sess.create_err(err).emit_unless(!self.include_lint_checks);
}
PatKind::Wild
}
@@ -508,12 +436,10 @@ impl<'tcx> ConstToPat<'tcx> {
if !pointee_ty.is_sized(tcx, param_env) {
// `tcx.deref_mir_constant()` below will ICE with an unsized type
// (except slices, which are handled in a separate arm above).
- let msg = format!("cannot use unsized non-slice type `{}` in constant patterns", pointee_ty);
- if self.include_lint_checks {
- tcx.sess.span_err(span, &msg);
- } else {
- tcx.sess.delay_span_bug(span, &msg);
- }
+
+ let err = UnsizedPattern { span, non_sm_ty: *pointee_ty };
+ tcx.sess.create_err(err).emit_unless(!self.include_lint_checks);
+
PatKind::Wild
} else {
let old = self.behind_reference.replace(true);
@@ -545,27 +471,19 @@ impl<'tcx> ConstToPat<'tcx> {
&& !self.saw_const_match_lint.get()
{
self.saw_const_match_lint.set(true);
- let msg = "function pointers and unsized pointers in patterns behave \
- unpredictably and should not be relied upon. \
- See https://github.com/rust-lang/rust/issues/70861 for details.";
- tcx.struct_span_lint_hir(
+ tcx.emit_spanned_lint(
lint::builtin::POINTER_STRUCTURAL_MATCH,
id,
span,
- msg,
- |lint| lint,
+ PointerPattern
);
}
PatKind::Constant { value: cv }
}
_ => {
self.saw_const_match_error.set(true);
- let msg = format!("`{}` cannot be used in patterns", cv.ty());
- if self.include_lint_checks {
- tcx.sess.span_err(span, &msg);
- } else {
- tcx.sess.delay_span_bug(span, &msg);
- }
+ let err = InvalidPattern { span, non_sm_ty: cv.ty() };
+ tcx.sess.create_err(err).emit_unless(!self.include_lint_checks);
PatKind::Wild
}
};
@@ -576,21 +494,17 @@ impl<'tcx> ConstToPat<'tcx> {
&& mir_structural_match_violation
// FIXME(#73448): Find a way to bring const qualification into parity with
// `search_for_structural_match_violation` and then remove this condition.
- && self.search_for_structural_match_violation(cv.ty()).is_some()
- {
- self.saw_const_match_lint.set(true);
+
// 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 msg = self.search_for_structural_match_violation(cv.ty()).unwrap().replace(
- "in a pattern,",
- "in a pattern, the constant's initializer must be trivial or",
- );
- tcx.struct_span_lint_hir(
+ && let Some(non_sm_ty) = traits::search_for_structural_match_violation(span, tcx, cv.ty())
+ {
+ self.saw_const_match_lint.set(true);
+ tcx.emit_spanned_lint(
lint::builtin::NONTRIVIAL_STRUCTURAL_MATCH,
id,
span,
- msg,
- |lint| lint,
+ NontrivialStructuralMatch {non_sm_ty}
);
}