diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 9c047cbfaef..784d6c3b2ce 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -742,6 +742,14 @@ rustc_queries! { desc { "destructure constant" } } + /// Dereference a constant reference or raw pointer and turn the result into a constant + /// again. + query deref_const( + key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>> + ) -> &'tcx ty::Const<'tcx> { + desc { "deref constant" } + } + query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> ConstValue<'tcx> { desc { "get a &core::panic::Location referring to a span" } } diff --git a/compiler/rustc_mir/src/const_eval/mod.rs b/compiler/rustc_mir/src/const_eval/mod.rs index c93feb5096b..978d2fe0004 100644 --- a/compiler/rustc_mir/src/const_eval/mod.rs +++ b/compiler/rustc_mir/src/const_eval/mod.rs @@ -2,11 +2,14 @@ use std::convert::TryFrom; +use rustc_hir::Mutability; use rustc_middle::mir; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::{source_map::DUMMY_SP, symbol::Symbol}; -use crate::interpret::{intern_const_alloc_recursive, ConstValue, InternKind, InterpCx}; +use crate::interpret::{ + intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, MemPlaceMeta, Scalar, +}; mod error; mod eval_queries; @@ -67,3 +70,39 @@ pub(crate) fn destructure_const<'tcx>( mir::DestructuredConst { variant, fields } } + +pub(crate) fn deref_const<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + val: &'tcx ty::Const<'tcx>, +) -> &'tcx ty::Const<'tcx> { + trace!("deref_const: {:?}", val); + let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false); + let op = ecx.const_to_op(val, None).unwrap(); + let mplace = ecx.deref_operand(op).unwrap(); + if let Scalar::Ptr(ptr) = mplace.ptr { + assert_eq!( + ecx.memory.get_raw(ptr.alloc_id).unwrap().mutability, + Mutability::Not, + "deref_const cannot be used with mutable allocations as \ + that could allow pattern matching to observe mutable statics", + ); + } + + let ty = match mplace.meta { + MemPlaceMeta::None => mplace.layout.ty, + MemPlaceMeta::Poison => bug!("poison metadata in `deref_const`: {:#?}", mplace), + // In case of unsized types, figure out the real type behind. + MemPlaceMeta::Meta(scalar) => match mplace.layout.ty.kind() { + ty::Str => bug!("there's no sized equivalent of a `str`"), + ty::Slice(elem_ty) => tcx.mk_array(elem_ty, scalar.to_machine_usize(&tcx).unwrap()), + _ => bug!( + "type {} should not have metadata, but had {:?}", + mplace.layout.ty, + mplace.meta + ), + }, + }; + + tcx.mk_const(ty::Const { val: ty::ConstKind::Value(op_to_const(&ecx, mplace.into())), ty }) +} diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs index a356ae1709d..c00c6860903 100644 --- a/compiler/rustc_mir/src/lib.rs +++ b/compiler/rustc_mir/src/lib.rs @@ -59,4 +59,8 @@ pub fn provide(providers: &mut Providers) { let (param_env, value) = param_env_and_value.into_parts(); const_eval::destructure_const(tcx, param_env, value) }; + providers.deref_const = |tcx, param_env_and_value| { + let (param_env, value) = param_env_and_value.into_parts(); + const_eval::deref_const(tcx, param_env, value) + }; } 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 2816bad7eab..a203b3a1428 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 @@ -3,7 +3,7 @@ use rustc_index::vec::Idx; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_middle::mir::Field; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; use rustc_session::lint; use rustc_span::Span; use rustc_trait_selection::traits::predicate_for_trait_def; @@ -28,10 +28,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { debug!("const_to_pat: cv={:#?} id={:?}", cv, id); debug!("const_to_pat: cv.ty={:?} span={:?}", cv.ty, span); - self.tcx.infer_ctxt().enter(|infcx| { + let pat = self.tcx.infer_ctxt().enter(|infcx| { let mut convert = ConstToPat::new(self, id, span, infcx); convert.to_pat(cv, mir_structural_match_violation) - }) + }); + + debug!("const_to_pat: pat={:?}", pat); + pat } } @@ -40,17 +43,44 @@ struct ConstToPat<'a, 'tcx> { span: Span, param_env: ty::ParamEnv<'tcx>, - // This tracks if we signal some hard error for a given const value, so that + // This tracks if we emitted some hard error for a given const value, so that // we will not subsequently issue an irrelevant lint for the same const // value. saw_const_match_error: Cell, + // This tracks if we emitted some diagnostic for a given const value, so that + // we will not subsequently issue an irrelevant lint for the same const + // value. + saw_const_match_lint: Cell, + + // For backcompat we need to keep allowing non-structurally-eq types behind references. + // See also all the `cant-hide-behind` tests. + behind_reference: Cell, + // inference context used for checking `T: Structural` bounds. infcx: InferCtxt<'a, 'tcx>, include_lint_checks: bool, } +mod fallback_to_const_ref { + #[derive(Debug)] + /// This error type signals that we encountered a non-struct-eq situation behind a reference. + /// We bubble this up in order to get back to the reference destructuring and make that emit + /// a const pattern instead of a deref pattern. This allows us to simply call `PartialEq::eq` + /// on such patterns (since that function takes a reference) and not have to jump through any + /// hoops to get a reference to the value. + pub(super) struct FallbackToConstRef(()); + + pub(super) fn fallback_to_const_ref<'a, 'tcx>( + c2p: &super::ConstToPat<'a, 'tcx>, + ) -> FallbackToConstRef { + assert!(c2p.behind_reference.get()); + FallbackToConstRef(()) + } +} +use fallback_to_const_ref::{fallback_to_const_ref, FallbackToConstRef}; + impl<'a, 'tcx> ConstToPat<'a, 'tcx> { fn new( pat_ctxt: &PatCtxt<'_, 'tcx>, @@ -65,6 +95,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { param_env: pat_ctxt.param_env, include_lint_checks: pat_ctxt.include_lint_checks, saw_const_match_error: Cell::new(false), + saw_const_match_lint: Cell::new(false), + behind_reference: Cell::new(false), } } @@ -72,11 +104,44 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { self.infcx.tcx } - fn search_for_structural_match_violation( - &self, - ty: Ty<'tcx>, - ) -> Option> { - traits::search_for_structural_match_violation(self.id, self.span, self.tcx(), ty) + fn adt_derive_msg(&self, adt_def: &AdtDef) -> 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.id, self.span, self.tcx(), ty).map( + |non_sm_ty| { + with_no_trimmed_paths(|| match non_sm_ty { + traits::NonStructuralMatchTy::Adt(adt) => self.adt_derive_msg(adt), + traits::NonStructuralMatchTy::Dynamic => { + "trait objects cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTy::Opaque => { + "opaque types cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTy::Generator => { + "generators cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTy::Closure => { + "closures cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTy::Param => { + bug!("use of a constant whose type is a parameter inside a pattern") + } + traits::NonStructuralMatchTy::Projection => { + bug!("use of a constant whose type is a projection inside a pattern") + } + traits::NonStructuralMatchTy::Foreign => { + bug!("use of a value of a foreign type inside a pattern") + } + }) + }, + ) } fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool { @@ -95,7 +160,7 @@ impl<'a, 'tcx> ConstToPat<'a, '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); + let inlined_const_as_pat = self.recur(cv, mir_structural_match_violation).unwrap(); if self.include_lint_checks && !self.saw_const_match_error.get() { // If we were able to successfully convert the const to some pat, @@ -118,70 +183,11 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { return inlined_const_as_pat; } - if let Some(non_sm_ty) = structural { - let msg = with_no_trimmed_paths(|| match non_sm_ty { - traits::NonStructuralMatchTy::Adt(adt_def) => { - 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, - ) - } - traits::NonStructuralMatchTy::Dynamic => { - "trait objects cannot be used in patterns".to_string() - } - traits::NonStructuralMatchTy::Opaque => { - "opaque types cannot be used in patterns".to_string() - } - traits::NonStructuralMatchTy::Generator => { - "generators cannot be used in patterns".to_string() - } - traits::NonStructuralMatchTy::Closure => { - "closures cannot be used in patterns".to_string() - } - traits::NonStructuralMatchTy::Param => { - bug!("use of a constant whose type is a parameter inside a pattern") - } - traits::NonStructuralMatchTy::Projection => { - bug!("use of a constant whose type is a projection inside a pattern") - } - traits::NonStructuralMatchTy::Foreign => { - bug!("use of a value of a foreign type inside a pattern") - } - }); - - // double-check there even *is* a semantic `PartialEq` to dispatch to. - // - // (If there isn't, then we can safely issue a hard - // error, because that's never worked, due to compiler - // using `PartialEq::eq` in this scenario in the past.) - // - // Note: To fix rust-lang/rust#65466, one could lift this check - // *before* any structural-match checking, and unconditionally error - // if `PartialEq` is not implemented. However, that breaks stable - // code at the moment, because types like `for <'a> fn(&'a ())` do - // not *yet* implement `PartialEq`. So for now we leave this here. - let ty_is_partial_eq: bool = { - let partial_eq_trait_id = - self.tcx().require_lang_item(hir::LangItem::PartialEq, Some(self.span)); - let obligation: PredicateObligation<'_> = predicate_for_trait_def( - self.tcx(), - self.param_env, - ObligationCause::misc(self.span, self.id), - partial_eq_trait_id, - 0, - cv.ty, - &[], - ); - // FIXME: should this call a `predicate_must_hold` variant instead? - self.infcx.predicate_may_hold(&obligation) - }; - - if !ty_is_partial_eq { + if let Some(msg) = 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); - } else if mir_structural_match_violation { + } else if mir_structural_match_violation && !self.saw_const_match_lint.get() { self.tcx().struct_span_lint_hir( lint::builtin::INDIRECT_STRUCTURAL_MATCH, self.id, @@ -200,19 +206,57 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { inlined_const_as_pat } + fn type_may_have_partial_eq_impl(&self, ty: Ty<'tcx>) -> bool { + // double-check there even *is* a semantic `PartialEq` to dispatch to. + // + // (If there isn't, then we can safely issue a hard + // error, because that's never worked, due to compiler + // using `PartialEq::eq` in this scenario in the past.) + let partial_eq_trait_id = + self.tcx().require_lang_item(hir::LangItem::PartialEq, Some(self.span)); + let obligation: PredicateObligation<'_> = predicate_for_trait_def( + self.tcx(), + self.param_env, + ObligationCause::misc(self.span, self.id), + partial_eq_trait_id, + 0, + ty, + &[], + ); + // FIXME: should this call a `predicate_must_hold` variant instead? + + let has_impl = self.infcx.predicate_may_hold(&obligation); + + // Note: To fix rust-lang/rust#65466, we could just remove this type + // walk hack for function pointers, and unconditionally error + // if `PartialEq` is not implemented. However, that breaks stable + // code at the moment, because types like `for <'a> fn(&'a ())` do + // not *yet* implement `PartialEq`. So for now we leave this here. + has_impl + || ty.walk().any(|t| match t.unpack() { + ty::subst::GenericArgKind::Lifetime(_) => false, + ty::subst::GenericArgKind::Type(t) => t.is_fn_ptr(), + ty::subst::GenericArgKind::Const(_) => false, + }) + } + // Recursive helper for `to_pat`; invoke that (instead of calling this directly). - fn recur(&self, cv: &'tcx ty::Const<'tcx>) -> Pat<'tcx> { + fn recur( + &self, + cv: &'tcx ty::Const<'tcx>, + mir_structural_match_violation: bool, + ) -> Result, FallbackToConstRef> { let id = self.id; let span = self.span; let tcx = self.tcx(); let param_env = self.param_env; - let field_pats = |vals: &[&'tcx ty::Const<'tcx>]| { + let field_pats = |vals: &[&'tcx ty::Const<'tcx>]| -> Result<_, _> { vals.iter() .enumerate() .map(|(idx, val)| { let field = Field::new(idx); - FieldPat { field, pattern: self.recur(val) } + Ok(FieldPat { field, pattern: self.recur(val, false)? }) }) .collect() }; @@ -230,10 +274,63 @@ impl<'a, 'tcx> ConstToPat<'a, '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); - tcx.sess.span_err(span, "cannot use unions in constant patterns"); + 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) + } PatKind::Wild } - // keep old code until future-compat upgraded to errors. + 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 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) + } + 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. + // So instead of specific errors, you just get blanket errors about the whole + // const type. See + // https://github.com/rust-lang/rust/pull/70743#discussion_r404701963 for + // 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.include_lint_checks + && !self.saw_const_match_error.get() + && !self.saw_const_match_lint.get() + { + self.saw_const_match_lint.set(true); + let msg = format!( + "to use a constant of type `{}` in a pattern, \ + `{}` must be annotated with `#[derive(PartialEq, Eq)]`", + cv.ty, cv.ty, + ); + tcx.struct_span_lint_hir( + lint::builtin::INDIRECT_STRUCTURAL_MATCH, + id, + span, + |lint| lint.build(&msg).emit(), + ); + } + // Since we are behind a reference, we can just bubble the error up so we get a + // constant at reference type, making it easy to let the fallback call + // `PartialEq::eq` on it. + return Err(fallback_to_const_ref(self)); + } 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); let path = tcx.def_path_str(adt_def.did); @@ -243,29 +340,11 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { path, path, ); self.saw_const_match_error.set(true); - tcx.sess.span_err(span, &msg); - PatKind::Wild - } - // keep old code until future-compat upgraded to errors. - ty::Ref(_, adt_ty, _) if adt_ty.is_adt() && !self.type_marked_structural(adt_ty) => { - let adt_def = - if let ty::Adt(adt_def, _) = adt_ty.kind() { adt_def } else { unreachable!() }; - - debug!( - "adt_def {:?} has !type_marked_structural for adt_ty: {:?}", - adt_def, adt_ty - ); - - // HACK(estebank): Side-step ICE #53708, but anything other than erroring here - // would be wrong. Returnging `PatKind::Wild` is not technically correct. - 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); - tcx.sess.span_err(span, &msg); + if self.include_lint_checks { + tcx.sess.span_err(span, &msg); + } else { + tcx.sess.delay_span_bug(span, &msg) + } PatKind::Wild } ty::Adt(adt_def, substs) if adt_def.is_enum() => { @@ -276,30 +355,181 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { variant_index: destructured .variant .expect("destructed const of adt without variant id"), - subpatterns: field_pats(destructured.fields), + subpatterns: field_pats(destructured.fields)?, } } - ty::Adt(_, _) => { + ty::Tuple(_) | ty::Adt(_, _) => { let destructured = tcx.destructure_const(param_env.and(cv)); - PatKind::Leaf { subpatterns: field_pats(destructured.fields) } - } - ty::Tuple(_) => { - let destructured = tcx.destructure_const(param_env.and(cv)); - PatKind::Leaf { subpatterns: field_pats(destructured.fields) } + PatKind::Leaf { subpatterns: field_pats(destructured.fields)? } } ty::Array(..) => PatKind::Array { prefix: tcx .destructure_const(param_env.and(cv)) .fields .iter() - .map(|val| self.recur(val)) - .collect(), + .map(|val| self.recur(val, false)) + .collect::>()?, slice: None, suffix: Vec::new(), }, - _ => PatKind::Constant { value: cv }, + ty::Ref(_, pointee_ty, ..) => match *pointee_ty.kind() { + // 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) + } + PatKind::Wild + } + // `&str` and `&[u8]` are represented as `ConstValue::Slice`, let's keep using this + // optimization for now. + ty::Str => PatKind::Constant { value: cv }, + ty::Slice(elem_ty) if elem_ty == tcx.types.u8 => PatKind::Constant { value: cv }, + // `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. + // FIXME: clean this up, likely by permitting array patterns when matching on slices + ty::Array(elem_ty, _) if elem_ty == tcx.types.u8 => PatKind::Constant { value: cv }, + // Cannot merge this with the catch all branch below, because the `const_deref` + // changes the type from slice to array, and slice patterns behave differently from + // array patterns. + ty::Slice(..) => { + let old = self.behind_reference.replace(true); + let array = tcx.deref_const(self.param_env.and(cv)); + let val = PatKind::Deref { + subpattern: Pat { + kind: Box::new(PatKind::Slice { + prefix: tcx + .destructure_const(param_env.and(array)) + .fields + .iter() + .map(|val| self.recur(val, false)) + .collect::>()?, + slice: None, + suffix: vec![], + }), + span, + ty: pointee_ty, + }, + }; + self.behind_reference.set(old); + val + } + // Backwards compatibility hack: support references to non-structural types. + // We'll lower + // 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) => { + 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( + lint::builtin::INDIRECT_STRUCTURAL_MATCH, + self.id, + self.span, + |lint| lint.build(&msg).emit(), + ); + } + 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) + } + } + PatKind::Wild + } + } + // All other references are converted into deref patterns and then recursively + // convert the dereferenced constant to a pattern that is the sub-pattern of the + // deref pattern. + _ => { + let old = self.behind_reference.replace(true); + // In case there are structural-match violations somewhere in this subpattern, + // we fall back to a const pattern. If we do not do this, we may end up with + // a !structural-match constant that is not of reference type, which makes it + // very hard to invoke `PartialEq::eq` on it as a fallback. + let val = match self.recur(tcx.deref_const(self.param_env.and(cv)), false) { + Ok(subpattern) => PatKind::Deref { subpattern }, + Err(_) => PatKind::Constant { value: cv }, + }; + self.behind_reference.set(old); + val + } + }, + ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::FnDef(..) => { + PatKind::Constant { value: cv } + } + ty::RawPtr(pointee) if pointee.ty.is_sized(tcx.at(span), param_env) => { + PatKind::Constant { value: cv } + } + // FIXME: these can have very suprising 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.include_lint_checks + && !self.saw_const_match_error.get() + && !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( + lint::builtin::POINTER_STRUCTURAL_MATCH, + id, + span, + |lint| lint.build(&msg).emit(), + ); + } + 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) + } + PatKind::Wild + } }; - Pat { span, ty: cv.ty, kind: Box::new(kind) } + if self.include_lint_checks + && !self.saw_const_match_error.get() + && !self.saw_const_match_lint.get() + && 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( + lint::builtin::NONTRIVIAL_STRUCTURAL_MATCH, + id, + span, + |lint| lint.build(&msg).emit(), + ); + } + + Ok(Pat { span, ty: cv.ty, kind: Box::new(kind) }) } } diff --git a/compiler/rustc_session/src/lint/builtin.rs b/compiler/rustc_session/src/lint/builtin.rs index 562df176b14..13a4057a35b 100644 --- a/compiler/rustc_session/src/lint/builtin.rs +++ b/compiler/rustc_session/src/lint/builtin.rs @@ -2138,22 +2138,16 @@ declare_lint! { /// ```rust,compile_fail /// #![deny(indirect_structural_match)] /// - /// struct Plus(i32, i32); - /// const ONE_PLUS_TWO: &&Plus = &&Plus(1, 2); - /// - /// impl PartialEq for Plus { - /// fn eq(&self, other: &Self) -> bool { - /// self.0 + self.1 == other.0 + other.1 - /// } - /// } - /// - /// impl Eq for Plus {} - /// + /// struct NoDerive(i32); + /// impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } + /// impl Eq for NoDerive { } + /// #[derive(PartialEq, Eq)] + /// struct WrapParam(T); + /// const WRAP_INDIRECT_PARAM: & &WrapParam = & &WrapParam(NoDerive(0)); /// fn main() { - /// if let ONE_PLUS_TWO = &&Plus(3, 0) { - /// println!("semantic!"); - /// } else { - /// println!("structural!"); + /// match WRAP_INDIRECT_PARAM { + /// WRAP_INDIRECT_PARAM => { } + /// _ => { } /// } /// } /// ``` @@ -2170,9 +2164,8 @@ declare_lint! { /// [issue #62411]: https://github.com/rust-lang/rust/issues/62411 /// [future-incompatible]: ../index.md#future-incompatible-lints pub INDIRECT_STRUCTURAL_MATCH, - // defaulting to allow until rust-lang/rust#62614 is fixed. - Allow, - "pattern with const indirectly referencing non-structural-match type", + Warn, + "constant used in pattern contains value of non-structural-match type in a field or a variant", @future_incompatible = FutureIncompatibleInfo { reference: "issue #62411 ", edition: None, @@ -2197,6 +2190,83 @@ declare_lint! { report_in_external_macro } +declare_lint! { + /// The `pointer_structural_match` lint detects pointers used in patterns whose behaviour + /// cannot be relied upon across compiler versions and optimization levels. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(pointer_structural_match)] + /// fn foo(a: usize, b: usize) -> usize { a + b } + /// const FOO: fn(usize, usize) -> usize = foo; + /// fn main() { + /// match FOO { + /// FOO => {}, + /// _ => {}, + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Previous versions of Rust allowed function pointers and wide raw pointers in patterns. + /// While these work in many cases as expected by users, it is possible that due to + /// optimizations pointers are "not equal to themselves" or pointers to different functions + /// compare as equal during runtime. This is because LLVM optimizations can deduplicate + /// functions if their bodies are the same, thus also making pointers to these functions point + /// to the same location. Additionally functions may get duplicated if they are instantiated + /// in different crates and not deduplicated again via LTO. + pub POINTER_STRUCTURAL_MATCH, + Allow, + "pointers are not structural-match", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #62411 ", + edition: None, + }; +} + +declare_lint! { + /// The `nontrivial_structural_match` lint detects constants that are used in patterns, + /// whose type is not structural-match and whose initializer body actually uses values + /// that are not structural-match. So `Option` is ok if the constant + /// is just `None`. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(nontrivial_structural_match)] + /// + /// #[derive(Copy, Clone, Debug)] + /// struct NoDerive(u32); + /// impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } + /// impl Eq for NoDerive { } + /// fn main() { + /// const INDEX: Option = [None, Some(NoDerive(10))][0]; + /// match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), }; + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Previous versions of Rust accepted constants in patterns, even if those constants's types + /// did not have `PartialEq` derived. Thus the compiler falls back to runtime execution of + /// `PartialEq`, which can report that two constants are not equal even if they are + /// bit-equivalent. + pub NONTRIVIAL_STRUCTURAL_MATCH, + Warn, + "constant used in pattern of non-structural-match type and the constant's initializer \ + expression contains values of non-structural-match types", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #73448 ", + edition: None, + }; +} + declare_lint! { /// The `ambiguous_associated_items` lint detects ambiguity between /// [associated items] and [enum variants]. @@ -2630,6 +2700,8 @@ declare_lint_pass! { AMBIGUOUS_ASSOCIATED_ITEMS, MUTABLE_BORROW_RESERVATION_CONFLICT, INDIRECT_STRUCTURAL_MATCH, + POINTER_STRUCTURAL_MATCH, + NONTRIVIAL_STRUCTURAL_MATCH, SOFT_UNSTABLE, INLINE_NO_SANITIZE, ASM_SUB_REGISTER, diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index c83e996634c..2663f682a1d 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -94,7 +94,7 @@ pub struct OsString { // `OsStr::from_inner` current implementation relies // on `OsStr` being layout-compatible with `Slice`. // When attribute privacy is implemented, `OsStr` should be annotated as `#[repr(transparent)]`. -// Anyway, `OsStr` representation and layout are considered implementation detail, are +// Anyway, `OsStr` representation and layout are considered implementation details, are // not documented and must not be relied upon. pub struct OsStr { inner: Slice, diff --git a/src/test/ui/consts/const_in_pattern/cross-crate-fail.rs b/src/test/ui/consts/const_in_pattern/cross-crate-fail.rs index 05c53e5edcc..ab297f54dff 100644 --- a/src/test/ui/consts/const_in_pattern/cross-crate-fail.rs +++ b/src/test/ui/consts/const_in_pattern/cross-crate-fail.rs @@ -12,7 +12,6 @@ fn main() { match None { consts::SOME => panic!(), //~^ must be annotated with `#[derive(PartialEq, Eq)]` - //~| must be annotated with `#[derive(PartialEq, Eq)]` _ => {} } @@ -20,7 +19,6 @@ fn main() { match None { ::SOME => panic!(), //~^ must be annotated with `#[derive(PartialEq, Eq)]` - //~| must be annotated with `#[derive(PartialEq, Eq)]` _ => {} } diff --git a/src/test/ui/consts/const_in_pattern/cross-crate-fail.stderr b/src/test/ui/consts/const_in_pattern/cross-crate-fail.stderr index 95db19e342a..a8066a88c35 100644 --- a/src/test/ui/consts/const_in_pattern/cross-crate-fail.stderr +++ b/src/test/ui/consts/const_in_pattern/cross-crate-fail.stderr @@ -5,22 +5,10 @@ LL | consts::SOME => panic!(), | ^^^^^^^^^^^^ error: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/cross-crate-fail.rs:21:9 + --> $DIR/cross-crate-fail.rs:20:9 | LL | ::SOME => panic!(), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/cross-crate-fail.rs:13:9 - | -LL | consts::SOME => panic!(), - | ^^^^^^^^^^^^ - -error: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/cross-crate-fail.rs:21:9 - | -LL | ::SOME => panic!(), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.rs b/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.rs index a1f9838ca08..856d204178d 100644 --- a/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.rs +++ b/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.rs @@ -1,8 +1,5 @@ // check-pass -#![warn(indirect_structural_match)] -//~^ NOTE lint level is defined here - struct CustomEq; impl Eq for CustomEq {} @@ -32,7 +29,8 @@ fn main() { BAR_BAZ => panic!(), //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` //~| WARN this was previously accepted - //~| NOTE see issue #62411 + //~| NOTE see issue #73448 + //~| NOTE `#[warn(nontrivial_structural_match)]` on by default _ => {} } } diff --git a/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr b/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr index 0be1cca806e..e51d6f91649 100644 --- a/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr +++ b/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr @@ -1,16 +1,12 @@ -warning: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/custom-eq-branch-warn.rs:32:9 +warning: to use a constant of type `CustomEq` in a pattern, the constant's initializer must be trivial or `CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/custom-eq-branch-warn.rs:29:9 | LL | BAR_BAZ => panic!(), | ^^^^^^^ | -note: the lint level is defined here - --> $DIR/custom-eq-branch-warn.rs:3:9 - | -LL | #![warn(indirect_structural_match)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(nontrivial_structural_match)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #73448 warning: 1 warning emitted diff --git a/src/test/ui/consts/const_in_pattern/issue-65466.rs b/src/test/ui/consts/const_in_pattern/issue-65466.rs index 0e3e0f6dd88..2b421f4c705 100644 --- a/src/test/ui/consts/const_in_pattern/issue-65466.rs +++ b/src/test/ui/consts/const_in_pattern/issue-65466.rs @@ -1,9 +1,7 @@ -// FIXME: This still ICEs. -// -// ignore-test - #![deny(indirect_structural_match)] +// check-pass + #[derive(PartialEq, Eq)] enum O { Some(*const T), // Can also use PhantomData diff --git a/src/test/ui/consts/const_in_pattern/issue-65466.stderr b/src/test/ui/consts/const_in_pattern/issue-65466.stderr deleted file mode 100644 index 9fe3049d1d8..00000000000 --- a/src/test/ui/consts/const_in_pattern/issue-65466.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0601]: `main` function not found in crate `issue_65466` - --> $DIR/issue-65466.rs:1:1 - | -LL | / #![deny(indirect_structural_match)] -LL | | -LL | | #[derive(PartialEq, Eq)] -LL | | enum O { -... | -LL | | } -LL | | } - | |_^ consider adding a `main` function to `$DIR/issue-65466.rs` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0601`. diff --git a/src/test/ui/consts/const_in_pattern/no-eq-branch-fail.rs b/src/test/ui/consts/const_in_pattern/no-eq-branch-fail.rs index c7f02c615a0..fc80d51c72d 100644 --- a/src/test/ui/consts/const_in_pattern/no-eq-branch-fail.rs +++ b/src/test/ui/consts/const_in_pattern/no-eq-branch-fail.rs @@ -20,7 +20,6 @@ fn main() { match Foo::Qux(NoEq) { BAR_BAZ => panic!(), //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` _ => {} } } diff --git a/src/test/ui/consts/const_in_pattern/no-eq-branch-fail.stderr b/src/test/ui/consts/const_in_pattern/no-eq-branch-fail.stderr index ee78c6f5c3e..e505dad69be 100644 --- a/src/test/ui/consts/const_in_pattern/no-eq-branch-fail.stderr +++ b/src/test/ui/consts/const_in_pattern/no-eq-branch-fail.stderr @@ -4,11 +4,5 @@ error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated wit LL | BAR_BAZ => panic!(), | ^^^^^^^ -error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/no-eq-branch-fail.rs:21:9 - | -LL | BAR_BAZ => panic!(), - | ^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/consts/const_in_pattern/reject_non_structural.rs b/src/test/ui/consts/const_in_pattern/reject_non_structural.rs index bbeaeea1f87..7a8169bec45 100644 --- a/src/test/ui/consts/const_in_pattern/reject_non_structural.rs +++ b/src/test/ui/consts/const_in_pattern/reject_non_structural.rs @@ -39,51 +39,41 @@ fn main() { const ENUM: Derive = Derive::Some(NoDerive); match Derive::Some(NoDerive) { ENUM => dbg!(ENUM), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` const FIELD: OND = TrivialEq(Some(NoDerive)).0; match Some(NoDerive) { FIELD => dbg!(FIELD), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` const NO_DERIVE_SOME: OND = Some(NoDerive); const INDIRECT: OND = NO_DERIVE_SOME; match Some(NoDerive) {INDIRECT => dbg!(INDIRECT), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` const TUPLE: (OND, OND) = (None, Some(NoDerive)); match (None, Some(NoDerive)) { TUPLE => dbg!(TUPLE), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` const TYPE_ASCRIPTION: OND = Some(NoDerive): OND; match Some(NoDerive) { TYPE_ASCRIPTION => dbg!(TYPE_ASCRIPTION), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` const ARRAY: [OND; 2] = [None, Some(NoDerive)]; match [None, Some(NoDerive)] { ARRAY => dbg!(ARRAY), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` const REPEAT: [OND; 2] = [Some(NoDerive); 2]; match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` trait Trait: Sized { const ASSOC: Option; } impl Trait for NoDerive { const ASSOC: Option = Some(NoDerive); } match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` const BLOCK: OND = { NoDerive; Some(NoDerive) }; match Some(NoDerive) { BLOCK => dbg!(BLOCK), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` const ADDR_OF: &OND = &Some(NoDerive); match &Some(NoDerive) { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops"), }; diff --git a/src/test/ui/consts/const_in_pattern/reject_non_structural.stderr b/src/test/ui/consts/const_in_pattern/reject_non_structural.stderr index b1310cf101e..56405a55d69 100644 --- a/src/test/ui/consts/const_in_pattern/reject_non_structural.stderr +++ b/src/test/ui/consts/const_in_pattern/reject_non_structural.stderr @@ -5,61 +5,61 @@ LL | match Derive::Some(NoDerive) { ENUM => dbg!(ENUM), _ => panic!("whoops" | ^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:45:28 + --> $DIR/reject_non_structural.rs:44:28 | LL | match Some(NoDerive) { FIELD => dbg!(FIELD), _ => panic!("whoops"), }; | ^^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:51:27 + --> $DIR/reject_non_structural.rs:49:27 | LL | match Some(NoDerive) {INDIRECT => dbg!(INDIRECT), _ => panic!("whoops"), }; | ^^^^^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:56:36 + --> $DIR/reject_non_structural.rs:53:36 | LL | match (None, Some(NoDerive)) { TUPLE => dbg!(TUPLE), _ => panic!("whoops"), }; | ^^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:61:28 + --> $DIR/reject_non_structural.rs:57:28 | LL | match Some(NoDerive) { TYPE_ASCRIPTION => dbg!(TYPE_ASCRIPTION), _ => panic!("whoops"), }; | ^^^^^^^^^^^^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:66:36 + --> $DIR/reject_non_structural.rs:61:36 | LL | match [None, Some(NoDerive)] { ARRAY => dbg!(ARRAY), _ => panic!("whoops"), }; | ^^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:71:33 + --> $DIR/reject_non_structural.rs:65:33 | LL | match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), }; | ^^^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:71:33 + --> $DIR/reject_non_structural.rs:65:33 | LL | match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), }; | ^^^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:79:28 + --> $DIR/reject_non_structural.rs:71:28 | LL | match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), }; | ^^^^^^^^^^^^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:84:28 + --> $DIR/reject_non_structural.rs:75:28 | LL | match Some(NoDerive) { BLOCK => dbg!(BLOCK), _ => panic!("whoops"), }; | ^^^^^ warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:89:29 + --> $DIR/reject_non_structural.rs:79:29 | LL | match &Some(NoDerive) { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops"), }; | ^^^^^^^ @@ -72,65 +72,5 @@ LL | #![warn(indirect_structural_match)] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #62411 -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:40:36 - | -LL | match Derive::Some(NoDerive) { ENUM => dbg!(ENUM), _ => panic!("whoops"), }; - | ^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:45:28 - | -LL | match Some(NoDerive) { FIELD => dbg!(FIELD), _ => panic!("whoops"), }; - | ^^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:51:27 - | -LL | match Some(NoDerive) {INDIRECT => dbg!(INDIRECT), _ => panic!("whoops"), }; - | ^^^^^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:56:36 - | -LL | match (None, Some(NoDerive)) { TUPLE => dbg!(TUPLE), _ => panic!("whoops"), }; - | ^^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:61:28 - | -LL | match Some(NoDerive) { TYPE_ASCRIPTION => dbg!(TYPE_ASCRIPTION), _ => panic!("whoops"), }; - | ^^^^^^^^^^^^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:66:36 - | -LL | match [None, Some(NoDerive)] { ARRAY => dbg!(ARRAY), _ => panic!("whoops"), }; - | ^^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:71:33 - | -LL | match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), }; - | ^^^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:71:33 - | -LL | match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), }; - | ^^^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:79:28 - | -LL | match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), }; - | ^^^^^^^^^^^^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:84:28 - | -LL | match Some(NoDerive) { BLOCK => dbg!(BLOCK), _ => panic!("whoops"), }; - | ^^^^^ - -error: aborting due to 20 previous errors; 1 warning emitted +error: aborting due to 10 previous errors; 1 warning emitted diff --git a/src/test/ui/consts/const_in_pattern/warn_corner_cases.stderr b/src/test/ui/consts/const_in_pattern/warn_corner_cases.stderr index 3e7ed573c74..a24c8d18184 100644 --- a/src/test/ui/consts/const_in_pattern/warn_corner_cases.stderr +++ b/src/test/ui/consts/const_in_pattern/warn_corner_cases.stderr @@ -1,34 +1,30 @@ -warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` +warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/warn_corner_cases.rs:26:47 | LL | match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), }; | ^^^^^ | -note: the lint level is defined here - --> $DIR/warn_corner_cases.rs:15:9 - | -LL | #![warn(indirect_structural_match)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(nontrivial_structural_match)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #73448 -warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` +warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/warn_corner_cases.rs:32:47 | LL | match None { Some(_) => panic!("whoops"), CALL => dbg!(CALL), }; | ^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #73448 -warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` +warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/warn_corner_cases.rs:38:47 | LL | match None { Some(_) => panic!("whoops"), METHOD_CALL => dbg!(METHOD_CALL), }; | ^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #62411 + = note: for more information, see issue #73448 warning: 3 warnings emitted diff --git a/src/test/ui/consts/consts-in-patterns.rs b/src/test/ui/consts/consts-in-patterns.rs index d51215447d6..0295204c879 100644 --- a/src/test/ui/consts/consts-in-patterns.rs +++ b/src/test/ui/consts/consts-in-patterns.rs @@ -19,8 +19,6 @@ pub fn main() { assert_eq!(y, 2); let z = match &() { ZST => 9, - // FIXME: this should not be required - _ => 42, }; assert_eq!(z, 9); let z = match b"" { diff --git a/src/test/ui/consts/match_ice.rs b/src/test/ui/consts/match_ice.rs index 1e495438e83..632335c841e 100644 --- a/src/test/ui/consts/match_ice.rs +++ b/src/test/ui/consts/match_ice.rs @@ -9,11 +9,10 @@ fn main() { const C: &S = &S; match C { C => {} - //~^ ERROR to use a constant of type `S` in a pattern, `S` must be annotated with - //~| ERROR to use a constant of type `S` in a pattern, `S` must be annotated with + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` } const K: &T = &T; - match K { //~ ERROR non-exhaustive patterns: `&T` not covered + match K { K => {} } } diff --git a/src/test/ui/consts/match_ice.stderr b/src/test/ui/consts/match_ice.stderr index 5477170fb1e..699b4a5e200 100644 --- a/src/test/ui/consts/match_ice.stderr +++ b/src/test/ui/consts/match_ice.stderr @@ -4,24 +4,5 @@ error: to use a constant of type `S` in a pattern, `S` must be annotated with `# LL | C => {} | ^ -error[E0004]: non-exhaustive patterns: `&T` not covered - --> $DIR/match_ice.rs:16:11 - | -LL | struct T; - | --------- `T` defined here -... -LL | match K { - | ^ pattern `&T` not covered - | - = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `&T` +error: aborting due to previous error -error: to use a constant of type `S` in a pattern, `S` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/match_ice.rs:11:9 - | -LL | C => {} - | ^ - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/issues/issue-34784.rs b/src/test/ui/issues/issue-34784.rs index d3206e99430..98d943470a7 100644 --- a/src/test/ui/issues/issue-34784.rs +++ b/src/test/ui/issues/issue-34784.rs @@ -1,4 +1,6 @@ // run-pass + +#![warn(pointer_structural_match)] #![allow(dead_code)] const C: *const u8 = &0; diff --git a/src/test/ui/issues/issue-44333.rs b/src/test/ui/issues/issue-44333.rs index fffef975043..96e8795e52d 100644 --- a/src/test/ui/issues/issue-44333.rs +++ b/src/test/ui/issues/issue-44333.rs @@ -1,4 +1,7 @@ // run-pass + +#![warn(pointer_structural_match)] + type Func = fn(usize, usize) -> usize; fn foo(a: usize, b: usize) -> usize { a + b } @@ -13,8 +16,10 @@ const BAR: Func = bar; fn main() { match test(std::env::consts::ARCH.len()) { - FOO => println!("foo"), - BAR => println!("bar"), + FOO => println!("foo"), //~ WARN pointers in patterns behave unpredictably + //~^ WARN will become a hard error + BAR => println!("bar"), //~ WARN pointers in patterns behave unpredictably + //~^ WARN will become a hard error _ => unreachable!(), } } diff --git a/src/test/ui/issues/issue-44333.stderr b/src/test/ui/issues/issue-44333.stderr new file mode 100644 index 00000000000..8302b09e533 --- /dev/null +++ b/src/test/ui/issues/issue-44333.stderr @@ -0,0 +1,25 @@ +warning: 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. + --> $DIR/issue-44333.rs:19:9 + | +LL | FOO => println!("foo"), + | ^^^ + | +note: the lint level is defined here + --> $DIR/issue-44333.rs:3:9 + | +LL | #![warn(pointer_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #62411 + +warning: 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. + --> $DIR/issue-44333.rs:21:9 + | +LL | BAR => println!("bar"), + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #62411 + +warning: 2 warnings emitted + diff --git a/src/test/ui/match/issue-70972-dyn-trait.rs b/src/test/ui/match/issue-70972-dyn-trait.rs index a9b2699cafd..97d161c59ec 100644 --- a/src/test/ui/match/issue-70972-dyn-trait.rs +++ b/src/test/ui/match/issue-70972-dyn-trait.rs @@ -4,7 +4,7 @@ fn main() { let a: &dyn Send = &7u32; match a { F => panic!(), - //~^ ERROR trait objects cannot be used in patterns + //~^ ERROR `&dyn Send` cannot be used in patterns _ => {} } } diff --git a/src/test/ui/match/issue-70972-dyn-trait.stderr b/src/test/ui/match/issue-70972-dyn-trait.stderr index a4e827357de..7581070ebc1 100644 --- a/src/test/ui/match/issue-70972-dyn-trait.stderr +++ b/src/test/ui/match/issue-70972-dyn-trait.stderr @@ -1,4 +1,4 @@ -error: trait objects 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/src/test/ui/match/pattern-deref-miscompile.rs b/src/test/ui/match/pattern-deref-miscompile.rs new file mode 100644 index 00000000000..caa6d184a92 --- /dev/null +++ b/src/test/ui/match/pattern-deref-miscompile.rs @@ -0,0 +1,46 @@ +// run-pass + +fn main() { + match b"." as &[u8] { + b"." if true => {}, + b"." => panic!(), + b".." => panic!(), + b"" => panic!(), + _ => panic!(), + } + match b"." as &[u8] { + b"." if false => panic!(), + b"." => {}, + b".." => panic!(), + b"" => panic!(), + _ => panic!(), + } + match b".." as &[u8] { + b"." if true => panic!(), // the miscompile caused this arm to be reached + b"." => panic!(), + b".." => {}, + b"" => panic!(), + _ => panic!(), + } + match b".." as &[u8] { + b"." if false => panic!(), + b"." => panic!(), + b".." => {}, + b"" => panic!(), + _ => panic!(), + } + match b"" as &[u8] { + b"." if true => panic!(), + b"." => panic!(), + b".." => panic!(), + b"" => {}, + _ => panic!(), + } + match b"" as &[u8] { + b"." if false => panic!(), + b"." => panic!(), + b".." => panic!(), + b"" => {}, + _ => panic!(), + } +} diff --git a/src/test/ui/pattern/const-pat-ice.rs b/src/test/ui/pattern/const-pat-ice.rs index 06558767882..abfacf3936b 100644 --- a/src/test/ui/pattern/const-pat-ice.rs +++ b/src/test/ui/pattern/const-pat-ice.rs @@ -1,10 +1,4 @@ -// failure-status: 101 -// rustc-env:RUST_BACKTRACE=0 -// normalize-stderr-test "note: rustc 1.* running on .*" -> "note: rustc VERSION running on TARGET" -// normalize-stderr-test "note: compiler flags: .*" -> "note: compiler flags: FLAGS" -// normalize-stderr-test "/_match.rs:[0-9]+:[0-9]+" -> "/_match.rs:LL:CC" - -// This is a repro test for an ICE in our pattern handling of constants. +// check-pass const FOO: &&&u32 = &&&42; diff --git a/src/test/ui/pattern/const-pat-ice.stderr b/src/test/ui/pattern/const-pat-ice.stderr deleted file mode 100644 index 6b42c0e0848..00000000000 --- a/src/test/ui/pattern/const-pat-ice.stderr +++ /dev/null @@ -1,13 +0,0 @@ -thread 'rustc' panicked at 'assertion failed: rows.iter().all(|r| r.len() == v.len())', compiler/rustc_mir_build/src/thir/pattern/_match.rs:LL:CC -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace - -error: internal compiler error: unexpected panic - -note: the compiler unexpectedly panicked. this is a bug. - -note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md - -note: rustc VERSION running on TARGET - -note: compiler flags: FLAGS - diff --git a/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.rs b/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.rs index c5e4a72fb9f..65f27cf78f1 100644 --- a/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.rs +++ b/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.rs @@ -4,6 +4,7 @@ fn main() { const C: impl Copy = 0; match C { - C | _ => {} //~ ERROR: opaque types cannot be used in patterns + C | //~ ERROR: `impl Copy` cannot be used in patterns + _ => {} } } diff --git a/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.stderr b/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.stderr index 7695223f2cf..62dc856be82 100644 --- a/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.stderr +++ b/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.stderr @@ -1,7 +1,7 @@ -error: opaque types cannot be used in patterns +error: `impl Copy` cannot be used in patterns --> $DIR/issue-71042-opaquely-typed-constant-used-in-pattern.rs:7:9 | -LL | C | _ => {} +LL | C | | ^ error: aborting due to previous error diff --git a/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.rs b/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.rs index d379dc44bf1..78cc0d28fb0 100644 --- a/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.rs +++ b/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.rs @@ -160,7 +160,7 @@ fn main() { match &0 { &42 => {} &FOO => {} //~ ERROR unreachable pattern - BAR => {} // Not detected as unreachable because `try_eval_bits` fails on `BAR`. + BAR => {} //~ ERROR unreachable pattern _ => {} } diff --git a/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.stderr b/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.stderr index de831520598..9f076c50a8f 100644 --- a/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.stderr +++ b/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.stderr @@ -135,6 +135,12 @@ error: unreachable pattern LL | &FOO => {} | ^^^^ -error: aborting due to 15 previous errors +error: unreachable pattern + --> $DIR/exhaustive_integer_patterns.rs:163:9 + | +LL | BAR => {} + | ^^^ + +error: aborting due to 16 previous errors For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/slice-pattern-const-2.rs b/src/test/ui/pattern/usefulness/slice-pattern-const-2.rs index a36c550f530..4bf8d0fd2d3 100644 --- a/src/test/ui/pattern/usefulness/slice-pattern-const-2.rs +++ b/src/test/ui/pattern/usefulness/slice-pattern-const-2.rs @@ -6,19 +6,19 @@ fn main() { match s { MAGIC_TEST => (), [0x00, 0x00, 0x00, 0x00] => (), - [4, 5, 6, 7] => (), // FIXME(oli-obk): this should warn, but currently does not + [4, 5, 6, 7] => (), //~ ERROR unreachable pattern _ => (), } match s { [0x00, 0x00, 0x00, 0x00] => (), MAGIC_TEST => (), - [4, 5, 6, 7] => (), // FIXME(oli-obk): this should warn, but currently does not + [4, 5, 6, 7] => (), //~ ERROR unreachable pattern _ => (), } match s { [0x00, 0x00, 0x00, 0x00] => (), [4, 5, 6, 7] => (), - MAGIC_TEST => (), // FIXME(oli-obk): this should warn, but currently does not + MAGIC_TEST => (), //~ ERROR unreachable pattern _ => (), } const FOO: [u32; 1] = [4]; diff --git a/src/test/ui/pattern/usefulness/slice-pattern-const-2.stderr b/src/test/ui/pattern/usefulness/slice-pattern-const-2.stderr index cd0cb2e8876..dcad11a38a7 100644 --- a/src/test/ui/pattern/usefulness/slice-pattern-const-2.stderr +++ b/src/test/ui/pattern/usefulness/slice-pattern-const-2.stderr @@ -1,8 +1,8 @@ error: unreachable pattern - --> $DIR/slice-pattern-const-2.rs:28:9 + --> $DIR/slice-pattern-const-2.rs:9:9 | -LL | FOO => (), - | ^^^ +LL | [4, 5, 6, 7] => (), + | ^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/slice-pattern-const-2.rs:1:9 @@ -10,5 +10,23 @@ note: the lint level is defined here LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: unreachable pattern + --> $DIR/slice-pattern-const-2.rs:15:9 + | +LL | [4, 5, 6, 7] => (), + | ^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/slice-pattern-const-2.rs:21:9 + | +LL | MAGIC_TEST => (), + | ^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/slice-pattern-const-2.rs:28:9 + | +LL | FOO => (), + | ^^^ + +error: aborting due to 4 previous errors diff --git a/src/test/ui/pattern/usefulness/slice-pattern-const-3.rs b/src/test/ui/pattern/usefulness/slice-pattern-const-3.rs index 8805c43ba02..2ca8323f002 100644 --- a/src/test/ui/pattern/usefulness/slice-pattern-const-3.rs +++ b/src/test/ui/pattern/usefulness/slice-pattern-const-3.rs @@ -6,19 +6,19 @@ fn main() { match s { MAGIC_TEST => (), ["0x00", "0x00", "0x00", "0x00"] => (), - ["4", "5", "6", "7"] => (), // FIXME(oli-obk): this should warn, but currently does not + ["4", "5", "6", "7"] => (), //~ ERROR unreachable pattern _ => (), } match s { ["0x00", "0x00", "0x00", "0x00"] => (), MAGIC_TEST => (), - ["4", "5", "6", "7"] => (), // FIXME(oli-obk): this should warn, but currently does not + ["4", "5", "6", "7"] => (), //~ ERROR unreachable pattern _ => (), } match s { ["0x00", "0x00", "0x00", "0x00"] => (), ["4", "5", "6", "7"] => (), - MAGIC_TEST => (), // FIXME(oli-obk): this should warn, but currently does not + MAGIC_TEST => (), //~ ERROR unreachable pattern _ => (), } const FOO: [&str; 1] = ["boo"]; diff --git a/src/test/ui/pattern/usefulness/slice-pattern-const-3.stderr b/src/test/ui/pattern/usefulness/slice-pattern-const-3.stderr index 3ba01b9eba3..b90b3a88a18 100644 --- a/src/test/ui/pattern/usefulness/slice-pattern-const-3.stderr +++ b/src/test/ui/pattern/usefulness/slice-pattern-const-3.stderr @@ -1,8 +1,8 @@ error: unreachable pattern - --> $DIR/slice-pattern-const-3.rs:28:9 + --> $DIR/slice-pattern-const-3.rs:9:9 | -LL | FOO => (), - | ^^^ +LL | ["4", "5", "6", "7"] => (), + | ^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/slice-pattern-const-3.rs:1:9 @@ -10,5 +10,23 @@ note: the lint level is defined here LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: unreachable pattern + --> $DIR/slice-pattern-const-3.rs:15:9 + | +LL | ["4", "5", "6", "7"] => (), + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/slice-pattern-const-3.rs:21:9 + | +LL | MAGIC_TEST => (), + | ^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/slice-pattern-const-3.rs:28:9 + | +LL | FOO => (), + | ^^^ + +error: aborting due to 4 previous errors diff --git a/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs b/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs index 52d1320dad1..46e0da5be9b 100644 --- a/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs +++ b/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs @@ -6,15 +6,15 @@ fn main() { let s10: &[bool; 10] = &[false; 10]; match s2 { - //~^ ERROR `&[false, _]` not covered + //~^ ERROR `&[false, _]` not covered [true, .., true] => {} } match s3 { - //~^ ERROR `&[false, ..]` not covered + //~^ ERROR `&[false, ..]` not covered [true, .., true] => {} } match s10 { - //~^ ERROR `&[false, ..]` not covered + //~^ ERROR `&[false, ..]` not covered [true, .., true] => {} } @@ -23,58 +23,58 @@ fn main() { [.., false] => {} } match s2 { - //~^ ERROR `&[false, true]` not covered + //~^ ERROR `&[false, true]` not covered [true, ..] => {} [.., false] => {} } match s3 { - //~^ ERROR `&[false, .., true]` not covered + //~^ ERROR `&[false, .., true]` not covered [true, ..] => {} [.., false] => {} } match s { - //~^ ERROR `&[false, .., true]` not covered + //~^ ERROR `&[false, .., true]` not covered [] => {} [true, ..] => {} [.., false] => {} } match s { - //~^ ERROR `&[_, ..]` not covered + //~^ ERROR `&[_, ..]` not covered [] => {} } match s { - //~^ ERROR `&[_, _, ..]` not covered + //~^ ERROR `&[_, _, ..]` not covered [] => {} [_] => {} } match s { - //~^ ERROR `&[false, ..]` not covered + //~^ ERROR `&[false, ..]` not covered [] => {} [true, ..] => {} } match s { - //~^ ERROR `&[false, _, ..]` not covered + //~^ ERROR `&[false, _, ..]` not covered [] => {} [_] => {} [true, ..] => {} } match s { - //~^ ERROR `&[_, .., false]` not covered + //~^ ERROR `&[_, .., false]` not covered [] => {} [_] => {} [.., true] => {} } match s { - //~^ ERROR `&[_, _, .., true]` not covered + //~^ ERROR `&[_, _, .., true]` not covered [] => {} [_] => {} [_, _] => {} [.., false] => {} } match s { - //~^ ERROR `&[true, _, .., _]` not covered + //~^ ERROR `&[true, _, .., _]` not covered [] => {} [_] => {} [_, _] => {} @@ -83,19 +83,43 @@ fn main() { const CONST: &[bool] = &[true]; match s { - //~^ ERROR `&[..]` not covered + //~^ ERROR `&[]` and `&[_, _, ..]` not covered + &[true] => {} + } + match s { + //~^ ERROR `&[]` and `&[_, _, ..]` not covered CONST => {} } match s { - //~^ ERROR `&[true]` not covered - [] => {}, - [false] => {}, - CONST => {}, + //~^ ERROR `&[]` and `&[_, _, ..]` not covered + CONST => {} + &[false] => {} + } + match s { + //~^ ERROR `&[]` and `&[_, _, ..]` not covered + &[false] => {} + CONST => {} + } + match s { + //~^ ERROR `&[_, _, ..]` not covered + &[] => {} + CONST => {} + } + match s { + //~^ ERROR `&[false]` not covered + &[] => {} + CONST => {} + &[_, _, ..] => {} + } + match s { + [] => {} + [false] => {} + CONST => {} [_, _, ..] => {} } const CONST1: &[bool; 1] = &[true]; match s1 { - //~^ ERROR `&[false]` not covered + //~^ ERROR `&[false]` not covered CONST1 => {} } match s1 { diff --git a/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr b/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr index 8b85eaeda0a..e34770fb912 100644 --- a/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr +++ b/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr @@ -115,26 +115,62 @@ LL | match s { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `&[bool]` -error[E0004]: non-exhaustive patterns: `&[..]` not covered +error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered --> $DIR/slice-patterns-exhaustiveness.rs:85:11 | LL | match s { - | ^ pattern `&[..]` not covered + | ^ patterns `&[]` and `&[_, _, ..]` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `&[bool]` -error[E0004]: non-exhaustive patterns: `&[true]` not covered +error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered --> $DIR/slice-patterns-exhaustiveness.rs:89:11 | LL | match s { - | ^ pattern `&[true]` not covered + | ^ patterns `&[]` and `&[_, _, ..]` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `&[bool]` + +error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:93:11 + | +LL | match s { + | ^ patterns `&[]` and `&[_, _, ..]` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `&[bool]` + +error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:98:11 + | +LL | match s { + | ^ patterns `&[]` and `&[_, _, ..]` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `&[bool]` + +error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:103:11 + | +LL | match s { + | ^ pattern `&[_, _, ..]` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `&[bool]` error[E0004]: non-exhaustive patterns: `&[false]` not covered - --> $DIR/slice-patterns-exhaustiveness.rs:97:11 + --> $DIR/slice-patterns-exhaustiveness.rs:108:11 + | +LL | match s { + | ^ pattern `&[false]` not covered + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + = note: the matched value is of type `&[bool]` + +error[E0004]: non-exhaustive patterns: `&[false]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:121:11 | LL | match s1 { | ^^ pattern `&[false]` not covered @@ -142,6 +178,6 @@ LL | match s1 { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `&[bool; 1]` -error: aborting due to 16 previous errors +error: aborting due to 20 previous errors For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-embedded.rs b/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-embedded.rs index b90a750cc16..c6d7166e740 100644 --- a/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-embedded.rs +++ b/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-embedded.rs @@ -3,6 +3,8 @@ // run-pass +#![warn(pointer_structural_match)] + struct NoDerive(i32); // This impl makes NoDerive irreflexive diff --git a/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-param.rs b/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-param.rs index 1076b9f25d8..cc7ea6cde8d 100644 --- a/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-param.rs +++ b/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-param.rs @@ -3,6 +3,8 @@ // run-pass +#![warn(pointer_structural_match)] + struct NoDerive(i32); // This impl makes NoDerive irreflexive diff --git a/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-embedded.rs b/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-embedded.rs index a4b832d377d..86db09cc08f 100644 --- a/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-embedded.rs +++ b/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-embedded.rs @@ -3,6 +3,8 @@ // run-pass +#![warn(pointer_structural_match)] + struct NoDerive(i32); // This impl makes NoDerive irreflexive diff --git a/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-param.rs b/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-param.rs index 47b70e2e9cc..99c574d0780 100644 --- a/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-param.rs +++ b/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-param.rs @@ -3,6 +3,8 @@ // run-pass +#![warn(pointer_structural_match)] + struct NoDerive(i32); // This impl makes NoDerive irreflexive diff --git a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.rs b/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.rs index c663535e533..4a8a0949379 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.rs +++ b/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.rs @@ -21,7 +21,6 @@ fn main() { match WRAP_DIRECT_INLINE { WRAP_DIRECT_INLINE => { panic!("WRAP_DIRECT_INLINE matched itself"); } //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` _ => { println!("WRAP_DIRECT_INLINE did not match itself"); } } } diff --git a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.stderr b/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.stderr index 9c7d1f3a18f..c73a6cf1326 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.stderr +++ b/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.stderr @@ -4,11 +4,5 @@ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be ann LL | WRAP_DIRECT_INLINE => { panic!("WRAP_DIRECT_INLINE matched itself"); } | ^^^^^^^^^^^^^^^^^^ -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/cant-hide-behind-direct-struct-embedded.rs:22:9 - | -LL | WRAP_DIRECT_INLINE => { panic!("WRAP_DIRECT_INLINE matched itself"); } - | ^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.rs b/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.rs index 872bf5a63ff..93022a23dbf 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.rs +++ b/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.rs @@ -21,7 +21,6 @@ fn main() { match WRAP_DIRECT_PARAM { WRAP_DIRECT_PARAM => { panic!("WRAP_DIRECT_PARAM matched itself"); } //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` _ => { println!("WRAP_DIRECT_PARAM did not match itself"); } } } diff --git a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.stderr b/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.stderr index 6f49a8a0c9d..6fdf9db89b8 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.stderr +++ b/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.stderr @@ -4,11 +4,5 @@ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be ann LL | WRAP_DIRECT_PARAM => { panic!("WRAP_DIRECT_PARAM matched itself"); } | ^^^^^^^^^^^^^^^^^ -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/cant-hide-behind-direct-struct-param.rs:22:9 - | -LL | WRAP_DIRECT_PARAM => { panic!("WRAP_DIRECT_PARAM matched itself"); } - | ^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-embedded.rs b/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-embedded.rs index f6947819695..fe62774d220 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-embedded.rs +++ b/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-embedded.rs @@ -23,7 +23,7 @@ fn main() { match WRAP_DOUBLY_INDIRECT_INLINE { WRAP_DOUBLY_INDIRECT_INLINE => { panic!("WRAP_DOUBLY_INDIRECT_INLINE matched itself"); } //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` - //~| WARN will become a hard error in a future release + //~| WARN this was previously accepted _ => { println!("WRAP_DOUBLY_INDIRECT_INLINE correctly did not match itself"); } } } diff --git a/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-param.rs b/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-param.rs index 1c29d67b655..c3a30674ea3 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-param.rs +++ b/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-param.rs @@ -23,7 +23,7 @@ fn main() { match WRAP_DOUBLY_INDIRECT_PARAM { WRAP_DOUBLY_INDIRECT_PARAM => { panic!("WRAP_DOUBLY_INDIRECT_PARAM matched itself"); } //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` - //~| WARN will become a hard error in a future release + //~| WARN this was previously accepted _ => { println!("WRAP_DOUBLY_INDIRECT_PARAM correctly did not match itself"); } } } diff --git a/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-embedded.rs b/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-embedded.rs index 1a41dbb55c2..4d0e80d5af3 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-embedded.rs +++ b/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-embedded.rs @@ -23,7 +23,7 @@ fn main() { match WRAP_INDIRECT_INLINE { WRAP_INDIRECT_INLINE => { panic!("WRAP_INDIRECT_INLINE matched itself"); } //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` - //~| WARN will become a hard error in a future release + //~| WARN this was previously accepted _ => { println!("WRAP_INDIRECT_INLINE did not match itself"); } } } diff --git a/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-param.rs b/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-param.rs index 46032c4b0eb..432f196ec81 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-param.rs +++ b/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-param.rs @@ -23,7 +23,7 @@ fn main() { match WRAP_INDIRECT_PARAM { WRAP_INDIRECT_PARAM => { panic!("WRAP_INDIRECT_PARAM matched itself"); } //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` - //~| WARN will become a hard error in a future release + //~| WARN this was previously accepted _ => { println!("WRAP_INDIRECT_PARAM correctly did not match itself"); } } } diff --git a/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.rs b/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.rs index 6ebb948d736..46d8ee3b6be 100644 --- a/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.rs +++ b/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.rs @@ -10,7 +10,7 @@ // Issue 62307 pointed out a case where the structural-match checking // was too shallow. -#![warn(indirect_structural_match)] +#![warn(indirect_structural_match, nontrivial_structural_match)] // run-pass #[derive(Debug)] @@ -30,14 +30,14 @@ fn main() { match RR_B0 { RR_B1 => { println!("CLAIM RR0: {:?} matches {:?}", RR_B1, RR_B0); } //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` - //~| WARN will become a hard error in a future release + //~| WARN this was previously accepted _ => { } } match RR_B1 { RR_B1 => { println!("CLAIM RR1: {:?} matches {:?}", RR_B1, RR_B1); } //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` - //~| WARN will become a hard error in a future release + //~| WARN this was previously accepted _ => { } } } diff --git a/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.stderr b/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.stderr index ae011dfcdba..a50093a5b11 100644 --- a/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.stderr +++ b/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.stderr @@ -7,7 +7,7 @@ LL | RR_B1 => { println!("CLAIM RR0: {:?} matches {:?}", RR_B1, RR_B0); note: the lint level is defined here --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:13:9 | -LL | #![warn(indirect_structural_match)] +LL | #![warn(indirect_structural_match, nontrivial_structural_match)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #62411 diff --git a/src/test/ui/rfc1445/issue-63479-match-fnptr.rs b/src/test/ui/rfc1445/issue-63479-match-fnptr.rs index b3c91cec580..567685950e9 100644 --- a/src/test/ui/rfc1445/issue-63479-match-fnptr.rs +++ b/src/test/ui/rfc1445/issue-63479-match-fnptr.rs @@ -5,6 +5,8 @@ // cover the case this hit; I've since expanded it accordingly, but the // experience left me wary of leaving this regression test out.) +#![warn(pointer_structural_match)] + #[derive(Eq)] struct A { a: i64 @@ -31,6 +33,8 @@ fn main() { let s = B(my_fn); match s { B(TEST) => println!("matched"), + //~^ WARN pointers in patterns behave unpredictably + //~| WARN this was previously accepted by the compiler but is being phased out _ => panic!("didn't match") }; } diff --git a/src/test/ui/rfc1445/issue-63479-match-fnptr.stderr b/src/test/ui/rfc1445/issue-63479-match-fnptr.stderr new file mode 100644 index 00000000000..8cf87cc85a1 --- /dev/null +++ b/src/test/ui/rfc1445/issue-63479-match-fnptr.stderr @@ -0,0 +1,16 @@ +warning: 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. + --> $DIR/issue-63479-match-fnptr.rs:35:7 + | +LL | B(TEST) => println!("matched"), + | ^^^^ + | +note: the lint level is defined here + --> $DIR/issue-63479-match-fnptr.rs:8:9 + | +LL | #![warn(pointer_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #62411 + +warning: 1 warning emitted + diff --git a/src/test/ui/rfc1445/match-forbidden-without-eq.rs b/src/test/ui/rfc1445/match-forbidden-without-eq.rs index 59141eac3e8..1cca2752061 100644 --- a/src/test/ui/rfc1445/match-forbidden-without-eq.rs +++ b/src/test/ui/rfc1445/match-forbidden-without-eq.rs @@ -12,7 +12,6 @@ fn main() { match y { FOO => { } //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` _ => { } } diff --git a/src/test/ui/rfc1445/match-forbidden-without-eq.stderr b/src/test/ui/rfc1445/match-forbidden-without-eq.stderr index 1f26f0f11dc..02fa2398189 100644 --- a/src/test/ui/rfc1445/match-forbidden-without-eq.stderr +++ b/src/test/ui/rfc1445/match-forbidden-without-eq.stderr @@ -5,7 +5,7 @@ LL | FOO => { } | ^^^ warning: floating-point types cannot be used in patterns - --> $DIR/match-forbidden-without-eq.rs:21:9 + --> $DIR/match-forbidden-without-eq.rs:20:9 | LL | f32::INFINITY => { } | ^^^^^^^^^^^^^ @@ -14,14 +14,8 @@ LL | f32::INFINITY => { } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #41620 -error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/match-forbidden-without-eq.rs:13:9 - | -LL | FOO => { } - | ^^^ - warning: floating-point types cannot be used in patterns - --> $DIR/match-forbidden-without-eq.rs:21:9 + --> $DIR/match-forbidden-without-eq.rs:20:9 | LL | f32::INFINITY => { } | ^^^^^^^^^^^^^ @@ -29,5 +23,5 @@ LL | f32::INFINITY => { } = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #41620 -error: aborting due to 2 previous errors; 2 warnings emitted +error: aborting due to previous error; 2 warnings emitted diff --git a/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.rs b/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.rs index 4112e8f4517..151a475c919 100644 --- a/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.rs +++ b/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.rs @@ -15,6 +15,5 @@ fn main() { match [B(1)] { FOO => { } //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` } } diff --git a/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.stderr b/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.stderr index 7e354bf9ade..371f8a0aa1d 100644 --- a/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.stderr +++ b/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.stderr @@ -4,11 +4,5 @@ error: to use a constant of type `B` in a pattern, `B` must be annotated with `# LL | FOO => { } | ^^^ -error: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/match-nonempty-array-forbidden-without-eq.rs:16:9 - | -LL | FOO => { } - | ^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.rs b/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.rs index 9530a1ffec4..6b7d94603b5 100644 --- a/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.rs +++ b/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.rs @@ -16,7 +16,6 @@ fn main() { match y { FOO => { } //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` _ => { } } } diff --git a/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.stderr b/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.stderr index 7ef082852ba..4157cf65283 100644 --- a/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.stderr +++ b/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.stderr @@ -4,11 +4,5 @@ error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated wit LL | FOO => { } | ^^^ -error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/match-requires-both-partialeq-and-eq.rs:17:9 - | -LL | FOO => { } - | ^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs index 479d6cd9af7..d50835608fa 100644 --- a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs +++ b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs @@ -12,9 +12,9 @@ const LEAK_FREE: Bar = leak_free(); fn leak_free_test() { match todo!() { LEAK_FREE => (), - //~^ opaque types cannot be used in patterns + //~^ `impl Send` cannot be used in patterns _ => (), } } -fn main() { } +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr index ae0d8e8d423..889c4fd4b04 100644 --- a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr +++ b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr @@ -1,4 +1,4 @@ -error: opaque types cannot be used in patterns +error: `impl Send` cannot be used in patterns --> $DIR/structural-match-no-leak.rs:14:9 | LL | LEAK_FREE => (), diff --git a/src/test/ui/type-alias-impl-trait/structural-match.rs b/src/test/ui/type-alias-impl-trait/structural-match.rs index 481448d64b1..a3ff4ad1d47 100644 --- a/src/test/ui/type-alias-impl-trait/structural-match.rs +++ b/src/test/ui/type-alias-impl-trait/structural-match.rs @@ -13,9 +13,9 @@ const VALUE: Foo = value(); fn test() { match todo!() { VALUE => (), - //~^ opaque types cannot be used in patterns + //~^ `impl Send` cannot be used in patterns _ => (), } } -fn main() { } +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/structural-match.stderr b/src/test/ui/type-alias-impl-trait/structural-match.stderr index ad9036a87d1..262fd072613 100644 --- a/src/test/ui/type-alias-impl-trait/structural-match.stderr +++ b/src/test/ui/type-alias-impl-trait/structural-match.stderr @@ -1,4 +1,4 @@ -error: opaque types cannot be used in patterns +error: `impl Send` cannot be used in patterns --> $DIR/structural-match.rs:15:9 | LL | VALUE => (), diff --git a/src/test/ui/union/union-const-pat.rs b/src/test/ui/union/union-const-pat.rs index cb2248cc6d1..e7cb248a201 100644 --- a/src/test/ui/union/union-const-pat.rs +++ b/src/test/ui/union/union-const-pat.rs @@ -8,7 +8,6 @@ const C: U = U { a: 10 }; fn main() { match C { C => {} //~ ERROR cannot use unions in constant patterns - //~| ERROR cannot use unions in constant patterns _ => {} } } diff --git a/src/test/ui/union/union-const-pat.stderr b/src/test/ui/union/union-const-pat.stderr index bec720401b9..dc87f4de521 100644 --- a/src/test/ui/union/union-const-pat.stderr +++ b/src/test/ui/union/union-const-pat.stderr @@ -4,11 +4,5 @@ error: cannot use unions in constant patterns LL | C => {} | ^ -error: cannot use unions in constant patterns - --> $DIR/union-const-pat.rs:10:9 - | -LL | C => {} - | ^ - -error: aborting due to 2 previous errors +error: aborting due to previous error