Auto merge of #70743 - oli-obk:eager_const_to_pat_conversion, r=eddyb

Fully destructure constants into patterns

r? `@varkor`

as discussed in https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/constants.20in.20patterns/near/192789924

we should probably crater it once reviewed
This commit is contained in:
bors 2020-09-26 06:44:28 +00:00
commit fd15e6180d
66 changed files with 796 additions and 435 deletions

View File

@ -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" }
}

View File

@ -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 })
}

View File

@ -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)
};
}

View File

@ -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<bool>,
// 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<bool>,
// For backcompat we need to keep allowing non-structurally-eq types behind references.
// See also all the `cant-hide-behind` tests.
behind_reference: Cell<bool>,
// 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::NonStructuralMatchTy<'tcx>> {
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<String> {
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<Pat<'tcx>, 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<NonStructEq>`, even though `Option` is annotated with derive.
let msg = self.search_for_structural_match_violation(cv.ty).unwrap();
self.saw_const_match_error.set(true);
if self.include_lint_checks {
tcx.sess.span_err(self.span, &msg);
} else {
tcx.sess.delay_span_bug(self.span, &msg)
}
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::<Result<_, _>>()?,
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::<Result<_, _>>()?,
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<NonStructEq>`, even though `Option` is annotated with derive.
let msg = self.search_for_structural_match_violation(cv.ty).unwrap().replace(
"in a pattern,",
"in a pattern, the constant's initializer must be trivial or",
);
tcx.struct_span_lint_hir(
lint::builtin::NONTRIVIAL_STRUCTURAL_MATCH,
id,
span,
|lint| lint.build(&msg).emit(),
);
}
Ok(Pat { span, ty: cv.ty, kind: Box::new(kind) })
}
}

View File

@ -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>(T);
/// const WRAP_INDIRECT_PARAM: & &WrapParam<NoDerive> = & &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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/70861>",
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<NotStruturalMatch>` 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<NoDerive> = [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 <https://github.com/rust-lang/rust/issues/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,

View File

@ -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,

View File

@ -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 {
<Defaulted as consts::AssocConst>::SOME => panic!(),
//~^ must be annotated with `#[derive(PartialEq, Eq)]`
//~| must be annotated with `#[derive(PartialEq, Eq)]`
_ => {}
}

View File

@ -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 | <Defaulted as consts::AssocConst>::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 | <Defaulted as consts::AssocConst>::SOME => panic!(),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 4 previous errors
error: aborting due to 2 previous errors

View File

@ -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
_ => {}
}
}

View File

@ -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 <https://github.com/rust-lang/rust/issues/62411>
= note: for more information, see issue #73448 <https://github.com/rust-lang/rust/issues/73448>
warning: 1 warning emitted

View File

@ -1,9 +1,7 @@
// FIXME: This still ICEs.
//
// ignore-test
#![deny(indirect_structural_match)]
// check-pass
#[derive(PartialEq, Eq)]
enum O<T> {
Some(*const T), // Can also use PhantomData<T>

View File

@ -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<T> {
... |
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`.

View File

@ -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)]`
_ => {}
}
}

View File

@ -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

View File

@ -39,51 +39,41 @@ fn main() {
const ENUM: Derive<NoDerive> = 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<Self>; }
impl Trait for NoDerive { const ASSOC: Option<NoDerive> = 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"), };

View File

@ -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 <https://github.com/rust-lang/rust/issues/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

View File

@ -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 <https://github.com/rust-lang/rust/issues/62411>
= note: for more information, see issue #73448 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/62411>
= note: for more information, see issue #73448 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/62411>
= note: for more information, see issue #73448 <https://github.com/rust-lang/rust/issues/73448>
warning: 3 warnings emitted

View File

@ -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"" {

View File

@ -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 => {}
}
}

View File

@ -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`.

View File

@ -1,4 +1,6 @@
// run-pass
#![warn(pointer_structural_match)]
#![allow(dead_code)]
const C: *const u8 = &0;

View File

@ -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!(),
}
}

View File

@ -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 <https://github.com/rust-lang/rust/issues/70861>
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 <https://github.com/rust-lang/rust/issues/70861>
warning: 2 warnings emitted

View File

@ -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
_ => {}
}
}

View File

@ -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!(),

View File

@ -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!(),
}
}

View File

@ -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;

View File

@ -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

View File

@ -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
_ => {}
}
}

View File

@ -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

View File

@ -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
_ => {}
}

View File

@ -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`.

View File

@ -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];

View File

@ -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

View File

@ -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"];

View File

@ -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

View File

@ -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 {

View File

@ -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`.

View File

@ -3,6 +3,8 @@
// run-pass
#![warn(pointer_structural_match)]
struct NoDerive(i32);
// This impl makes NoDerive irreflexive

View File

@ -3,6 +3,8 @@
// run-pass
#![warn(pointer_structural_match)]
struct NoDerive(i32);
// This impl makes NoDerive irreflexive

View File

@ -3,6 +3,8 @@
// run-pass
#![warn(pointer_structural_match)]
struct NoDerive(i32);
// This impl makes NoDerive irreflexive

View File

@ -3,6 +3,8 @@
// run-pass
#![warn(pointer_structural_match)]
struct NoDerive(i32);
// This impl makes NoDerive irreflexive

View File

@ -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"); }
}
}

View File

@ -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

View File

@ -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"); }
}
}

View File

@ -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

View File

@ -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"); }
}
}

View File

@ -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"); }
}
}

View File

@ -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"); }
}
}

View File

@ -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"); }
}
}

View File

@ -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
_ => { }
}
}

View File

@ -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 <https://github.com/rust-lang/rust/issues/62411>

View File

@ -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")
};
}

View File

@ -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 <https://github.com/rust-lang/rust/issues/70861>
warning: 1 warning emitted

View File

@ -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)]`
_ => { }
}

View File

@ -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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/41620>
error: aborting due to 2 previous errors; 2 warnings emitted
error: aborting due to previous error; 2 warnings emitted

View File

@ -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)]`
}
}

View File

@ -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

View File

@ -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)]`
_ => { }
}
}

View File

@ -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

View File

@ -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() {}

View File

@ -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 => (),

View File

@ -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() {}

View File

@ -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 => (),

View File

@ -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
_ => {}
}
}

View File

@ -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