From 64d98f8ee037282c35007b64c2649055c56af1db Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:19:03 +0200 Subject: Merging upstream version 1.68.2+dfsg1. Signed-off-by: Daniel Baumann --- .../src/thir/pattern/const_to_pat.rs | 190 ++++++--------------- 1 file changed, 52 insertions(+), 138 deletions(-) (limited to 'compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs') 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 { - 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`, 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`, 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`, 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} ); } -- cgit v1.2.3