]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
bump version to 1.75.0+dfsg1-1~bpo12+pve1
[rustc.git] / compiler / rustc_mir_build / src / thir / pattern / const_to_pat.rs
CommitLineData
1b1a35ee 1use rustc_hir as hir;
fe692bf9 2use rustc_hir::def_id::DefId;
49aad941 3use rustc_index::Idx;
1b1a35ee 4use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
353b0b11
FG
5use rustc_infer::traits::Obligation;
6use rustc_middle::mir;
17df50a5 7use rustc_middle::thir::{FieldPat, Pat, PatKind};
fe692bf9 8use rustc_middle::ty::{self, Ty, TyCtxt, ValTree};
1b1a35ee 9use rustc_session::lint;
ed00b5ec 10use rustc_span::{ErrorGuaranteed, Span};
fe692bf9 11use rustc_target::abi::{FieldIdx, VariantIdx};
1b1a35ee 12use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
353b0b11 13use rustc_trait_selection::traits::{self, ObligationCause};
1b1a35ee
XL
14
15use std::cell::Cell;
16
17df50a5 17use super::PatCtxt;
9c376795 18use crate::errors::{
781aab86
FG
19 FloatPattern, IndirectStructuralMatch, InvalidPattern, NonPartialEqMatch,
20 NontrivialStructuralMatch, PointerPattern, TypeNotStructural, UnionPattern, UnsizedPattern,
9c376795 21};
1b1a35ee
XL
22
23impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
24 /// Converts an evaluated constant to a pattern (if possible).
25 /// This means aggregate values (like structs and enums) are converted
26 /// to a pattern that matches the value (as if you'd compared via structural equality).
781aab86
FG
27 ///
28 /// `cv` must be a valtree or a `mir::ConstValue`.
f2b60f7d 29 #[instrument(level = "debug", skip(self), ret)]
1b1a35ee
XL
30 pub(super) fn const_to_pat(
31 &self,
781aab86 32 cv: mir::Const<'tcx>,
1b1a35ee
XL
33 id: hir::HirId,
34 span: Span,
fe692bf9 35 check_body_for_struct_match_violation: Option<DefId>,
f2b60f7d 36 ) -> Box<Pat<'tcx>> {
2b03887a
FG
37 let infcx = self.tcx.infer_ctxt().build();
38 let mut convert = ConstToPat::new(self, id, span, infcx);
fe692bf9 39 convert.to_pat(cv, check_body_for_struct_match_violation)
1b1a35ee
XL
40 }
41}
42
2b03887a 43struct ConstToPat<'tcx> {
1b1a35ee
XL
44 id: hir::HirId,
45 span: Span,
46 param_env: ty::ParamEnv<'tcx>,
47
48 // This tracks if we emitted some hard error for a given const value, so that
49 // we will not subsequently issue an irrelevant lint for the same const
50 // value.
ed00b5ec 51 saw_const_match_error: Cell<Option<ErrorGuaranteed>>,
1b1a35ee
XL
52
53 // This tracks if we emitted some diagnostic for a given const value, so that
54 // we will not subsequently issue an irrelevant lint for the same const
55 // value.
56 saw_const_match_lint: Cell<bool>,
57
58 // For backcompat we need to keep allowing non-structurally-eq types behind references.
59 // See also all the `cant-hide-behind` tests.
60 behind_reference: Cell<bool>,
61
62 // inference context used for checking `T: Structural` bounds.
2b03887a 63 infcx: InferCtxt<'tcx>,
1b1a35ee 64
29967ef6 65 treat_byte_string_as_slice: bool,
1b1a35ee
XL
66}
67
49aad941 68/// This error type signals that we encountered a non-struct-eq situation.
781aab86
FG
69/// We will fall back to calling `PartialEq::eq` on such patterns,
70/// and exhaustiveness checking will consider them as matching nothing.
49aad941 71#[derive(Debug)]
781aab86 72struct FallbackToOpaqueConst;
1b1a35ee 73
2b03887a 74impl<'tcx> ConstToPat<'tcx> {
1b1a35ee
XL
75 fn new(
76 pat_ctxt: &PatCtxt<'_, 'tcx>,
77 id: hir::HirId,
78 span: Span,
2b03887a 79 infcx: InferCtxt<'tcx>,
1b1a35ee 80 ) -> Self {
29967ef6 81 trace!(?pat_ctxt.typeck_results.hir_owner);
1b1a35ee
XL
82 ConstToPat {
83 id,
84 span,
85 infcx,
86 param_env: pat_ctxt.param_env,
ed00b5ec 87 saw_const_match_error: Cell::new(None),
1b1a35ee
XL
88 saw_const_match_lint: Cell::new(false),
89 behind_reference: Cell::new(false),
29967ef6
XL
90 treat_byte_string_as_slice: pat_ctxt
91 .typeck_results
92 .treat_byte_string_as_slice
93 .contains(&id.local_id),
1b1a35ee
XL
94 }
95 }
96
97 fn tcx(&self) -> TyCtxt<'tcx> {
98 self.infcx.tcx
99 }
100
1b1a35ee
XL
101 fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool {
102 ty.is_structural_eq_shallow(self.infcx.tcx)
103 }
104
923072b8
FG
105 fn to_pat(
106 &mut self,
781aab86 107 cv: mir::Const<'tcx>,
fe692bf9 108 check_body_for_struct_match_violation: Option<DefId>,
f2b60f7d 109 ) -> Box<Pat<'tcx>> {
29967ef6 110 trace!(self.treat_byte_string_as_slice);
1b1a35ee
XL
111 // This method is just a wrapper handling a validity check; the heavy lifting is
112 // performed by the recursive `recur` method, which is not meant to be
113 // invoked except by this method.
114 //
115 // once indirect_structural_match is a full fledged error, this
116 // level of indirection can be eliminated
117
fe692bf9
FG
118 let mir_structural_match_violation = check_body_for_struct_match_violation.map(|def_id| {
119 // `mir_const_qualif` must be called with the `DefId` of the item where the const is
120 // defined, not where it is declared. The difference is significant for associated
121 // constants.
122 self.tcx().mir_const_qualif(def_id).custom_eq
123 });
124 debug!(?check_body_for_struct_match_violation, ?mir_structural_match_violation);
125
ed00b5ec
FG
126 let have_valtree =
127 matches!(cv, mir::Const::Ty(c) if matches!(c.kind(), ty::ConstKind::Value(_)));
fe692bf9 128 let inlined_const_as_pat = match cv {
781aab86 129 mir::Const::Ty(c) => match c.kind() {
fe692bf9
FG
130 ty::ConstKind::Param(_)
131 | ty::ConstKind::Infer(_)
132 | ty::ConstKind::Bound(_, _)
133 | ty::ConstKind::Placeholder(_)
134 | ty::ConstKind::Unevaluated(_)
135 | ty::ConstKind::Error(_)
136 | ty::ConstKind::Expr(_) => {
137 span_bug!(self.span, "unexpected const in `to_pat`: {:?}", c.kind())
138 }
139 ty::ConstKind::Value(valtree) => self
140 .recur(valtree, cv.ty(), mir_structural_match_violation.unwrap_or(false))
781aab86 141 .unwrap_or_else(|_: FallbackToOpaqueConst| {
fe692bf9
FG
142 Box::new(Pat {
143 span: self.span,
144 ty: cv.ty(),
145 kind: PatKind::Constant { value: cv },
146 })
147 }),
148 },
781aab86 149 mir::Const::Unevaluated(_, _) => {
fe692bf9
FG
150 span_bug!(self.span, "unevaluated const in `to_pat`: {cv:?}")
151 }
781aab86 152 mir::Const::Val(_, _) => Box::new(Pat {
fe692bf9
FG
153 span: self.span,
154 ty: cv.ty(),
155 kind: PatKind::Constant { value: cv },
156 }),
157 };
1b1a35ee 158
ed00b5ec 159 if self.saw_const_match_error.get().is_none() {
781aab86
FG
160 // If we were able to successfully convert the const to some pat (possibly with some
161 // lints, but no errors), double-check that all types in the const implement
162 // `Structural` and `PartialEq`.
1b1a35ee 163
9c376795
FG
164 let structural =
165 traits::search_for_structural_match_violation(self.span, self.tcx(), cv.ty());
1b1a35ee
XL
166 debug!(
167 "search_for_structural_match_violation cv.ty: {:?} returned: {:?}",
5099ac24
FG
168 cv.ty(),
169 structural
1b1a35ee
XL
170 );
171
172 // This can occur because const qualification treats all associated constants as
173 // opaque, whereas `search_for_structural_match_violation` tries to monomorphize them
174 // before it runs.
175 //
176 // FIXME(#73448): Find a way to bring const qualification into parity with
177 // `search_for_structural_match_violation`.
fe692bf9 178 if structural.is_none() && mir_structural_match_violation.unwrap_or(false) {
1b1a35ee
XL
179 warn!("MIR const-checker found novel structural match violation. See #73448.");
180 return inlined_const_as_pat;
181 }
182
9c376795 183 if let Some(non_sm_ty) = structural {
781aab86 184 if !self.type_has_partial_eq_impl(cv.ty()) {
ed00b5ec 185 let e = if let ty::Adt(def, ..) = non_sm_ty.kind() {
fe692bf9
FG
186 if def.is_union() {
187 let err = UnionPattern { span: self.span };
ed00b5ec 188 self.tcx().sess.emit_err(err)
fe692bf9
FG
189 } else {
190 // fatal avoids ICE from resolution of nonexistent method (rare case).
191 self.tcx()
192 .sess
ed00b5ec 193 .emit_fatal(TypeNotStructural { span: self.span, non_sm_ty })
fe692bf9
FG
194 }
195 } else {
196 let err = InvalidPattern { span: self.span, non_sm_ty };
ed00b5ec
FG
197 self.tcx().sess.emit_err(err)
198 };
781aab86 199 // All branches above emitted an error. Don't print any more lints.
ed00b5ec
FG
200 // We errored. Signal that in the pattern, so that follow up errors can be silenced.
201 let kind = PatKind::Error(e);
202 return Box::new(Pat { span: self.span, ty: cv.ty(), kind });
203 } else if let ty::Adt(..) = cv.ty().kind() && matches!(cv, mir::Const::Val(..)) {
204 // This branch is only entered when the current `cv` is `mir::Const::Val`.
205 // This is because `mir::Const::ty` has already been handled by `Self::recur`
206 // and the invalid types may be ignored.
207 let err = TypeNotStructural { span: self.span, non_sm_ty };
208 let e = self.tcx().sess.emit_err(err);
209 let kind = PatKind::Error(e);
210 return Box::new(Pat { span: self.span, ty: cv.ty(), kind });
fe692bf9
FG
211 } else if !self.saw_const_match_lint.get() {
212 if let Some(mir_structural_match_violation) = mir_structural_match_violation {
213 match non_sm_ty.kind() {
fe692bf9
FG
214 ty::Adt(..) if mir_structural_match_violation => {
215 self.tcx().emit_spanned_lint(
216 lint::builtin::INDIRECT_STRUCTURAL_MATCH,
217 self.id,
218 self.span,
219 IndirectStructuralMatch { non_sm_ty },
220 );
221 }
222 _ => {
223 debug!(
224 "`search_for_structural_match_violation` found one, but `CustomEq` was \
225 not in the qualifs for that `const`"
226 );
227 }
228 }
229 }
230 }
ed00b5ec
FG
231 } else if !have_valtree && !self.saw_const_match_lint.get() {
232 // The only way valtree construction can fail without the structural match
233 // checker finding a violation is if there is a pointer somewhere.
234 self.tcx().emit_spanned_lint(
235 lint::builtin::POINTER_STRUCTURAL_MATCH,
236 self.id,
237 self.span,
238 PointerPattern,
239 );
1b1a35ee 240 }
781aab86
FG
241
242 // Always check for `PartialEq`, even if we emitted other lints. (But not if there were
243 // any errors.) This ensures it shows up in cargo's future-compat reports as well.
244 if !self.type_has_partial_eq_impl(cv.ty()) {
245 self.tcx().emit_spanned_lint(
246 lint::builtin::CONST_PATTERNS_WITHOUT_PARTIAL_EQ,
247 self.id,
248 self.span,
249 NonPartialEqMatch { non_peq_ty: cv.ty() },
250 );
251 }
1b1a35ee
XL
252 }
253
254 inlined_const_as_pat
255 }
256
fe692bf9 257 #[instrument(level = "trace", skip(self), ret)]
781aab86 258 fn type_has_partial_eq_impl(&self, ty: Ty<'tcx>) -> bool {
1b1a35ee
XL
259 // double-check there even *is* a semantic `PartialEq` to dispatch to.
260 //
261 // (If there isn't, then we can safely issue a hard
262 // error, because that's never worked, due to compiler
263 // using `PartialEq::eq` in this scenario in the past.)
264 let partial_eq_trait_id =
265 self.tcx().require_lang_item(hir::LangItem::PartialEq, Some(self.span));
353b0b11 266 let partial_eq_obligation = Obligation::new(
1b1a35ee 267 self.tcx(),
353b0b11 268 ObligationCause::dummy(),
1b1a35ee 269 self.param_env,
49aad941 270 ty::TraitRef::new(self.tcx(), partial_eq_trait_id, [ty, ty]),
1b1a35ee 271 );
1b1a35ee 272
781aab86
FG
273 // This *could* accept a type that isn't actually `PartialEq`, because region bounds get
274 // ignored. However that should be pretty much impossible since consts that do not depend on
275 // generics can only mention the `'static` lifetime, and how would one have a type that's
276 // `PartialEq` for some lifetime but *not* for `'static`? If this ever becomes a problem
277 // we'll need to leave some sort of trace of this requirement in the MIR so that borrowck
278 // can ensure that the type really implements `PartialEq`.
279 self.infcx.predicate_must_hold_modulo_regions(&partial_eq_obligation)
1b1a35ee
XL
280 }
281
cdc7bbd5
XL
282 fn field_pats(
283 &self,
fe692bf9 284 vals: impl Iterator<Item = (ValTree<'tcx>, Ty<'tcx>)>,
781aab86 285 ) -> Result<Vec<FieldPat<'tcx>>, FallbackToOpaqueConst> {
cdc7bbd5 286 vals.enumerate()
fe692bf9 287 .map(|(idx, (val, ty))| {
353b0b11 288 let field = FieldIdx::new(idx);
fe692bf9
FG
289 // Patterns can only use monomorphic types.
290 let ty = self.tcx().normalize_erasing_regions(self.param_env, ty);
291 Ok(FieldPat { field, pattern: self.recur(val, ty, false)? })
cdc7bbd5
XL
292 })
293 .collect()
294 }
295
1b1a35ee 296 // Recursive helper for `to_pat`; invoke that (instead of calling this directly).
923072b8 297 #[instrument(skip(self), level = "debug")]
1b1a35ee
XL
298 fn recur(
299 &self,
fe692bf9
FG
300 cv: ValTree<'tcx>,
301 ty: Ty<'tcx>,
1b1a35ee 302 mir_structural_match_violation: bool,
781aab86 303 ) -> Result<Box<Pat<'tcx>>, FallbackToOpaqueConst> {
1b1a35ee
XL
304 let id = self.id;
305 let span = self.span;
306 let tcx = self.tcx();
307 let param_env = self.param_env;
308
fe692bf9 309 let kind = match ty.kind() {
1b1a35ee 310 ty::Float(_) => {
fe692bf9 311 self.saw_const_match_lint.set(true);
49aad941
FG
312 tcx.emit_spanned_lint(
313 lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
314 id,
315 span,
316 FloatPattern,
317 );
781aab86 318 return Err(FallbackToOpaqueConst);
1b1a35ee 319 }
1b1a35ee
XL
320 // If the type is not structurally comparable, just emit the constant directly,
321 // causing the pattern match code to treat it opaquely.
322 // FIXME: This code doesn't emit errors itself, the caller emits the errors.
323 // So instead of specific errors, you just get blanket errors about the whole
324 // const type. See
325 // https://github.com/rust-lang/rust/pull/70743#discussion_r404701963 for
326 // details.
327 // Backwards compatibility hack because we can't cause hard errors on these
328 // types, so we compare them via `PartialEq::eq` at runtime.
fe692bf9 329 ty::Adt(..) if !self.type_marked_structural(ty) && self.behind_reference.get() => {
ed00b5ec 330 if self.saw_const_match_error.get().is_none() && !self.saw_const_match_lint.get() {
1b1a35ee 331 self.saw_const_match_lint.set(true);
9c376795 332 tcx.emit_spanned_lint(
1b1a35ee
XL
333 lint::builtin::INDIRECT_STRUCTURAL_MATCH,
334 id,
335 span,
fe692bf9 336 IndirectStructuralMatch { non_sm_ty: ty },
1b1a35ee
XL
337 );
338 }
339 // Since we are behind a reference, we can just bubble the error up so we get a
340 // constant at reference type, making it easy to let the fallback call
341 // `PartialEq::eq` on it.
781aab86 342 return Err(FallbackToOpaqueConst);
1b1a35ee 343 }
add651ee 344 ty::FnDef(..) => {
ed00b5ec
FG
345 let e = tcx.sess.emit_err(InvalidPattern { span, non_sm_ty: ty });
346 self.saw_const_match_error.set(Some(e));
347 // We errored. Signal that in the pattern, so that follow up errors can be silenced.
348 PatKind::Error(e)
add651ee 349 }
fe692bf9
FG
350 ty::Adt(adt_def, _) if !self.type_marked_structural(ty) => {
351 debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, ty,);
fe692bf9 352 let err = TypeNotStructural { span, non_sm_ty: ty };
ed00b5ec
FG
353 let e = tcx.sess.emit_err(err);
354 self.saw_const_match_error.set(Some(e));
355 // We errored. Signal that in the pattern, so that follow up errors can be silenced.
356 PatKind::Error(e)
1b1a35ee 357 }
add651ee 358 ty::Adt(adt_def, args) if adt_def.is_enum() => {
fe692bf9
FG
359 let (&variant_index, fields) = cv.unwrap_branch().split_first().unwrap();
360 let variant_index =
361 VariantIdx::from_u32(variant_index.unwrap_leaf().try_to_u32().ok().unwrap());
1b1a35ee 362 PatKind::Variant {
5e7ed085 363 adt_def: *adt_def,
add651ee 364 args,
fe692bf9
FG
365 variant_index,
366 subpatterns: self.field_pats(
367 fields.iter().copied().zip(
368 adt_def.variants()[variant_index]
369 .fields
370 .iter()
add651ee 371 .map(|field| field.ty(self.tcx(), args)),
fe692bf9
FG
372 ),
373 )?,
1b1a35ee
XL
374 }
375 }
fe692bf9
FG
376 ty::Tuple(fields) => PatKind::Leaf {
377 subpatterns: self
378 .field_pats(cv.unwrap_branch().iter().copied().zip(fields.iter()))?,
379 },
ed00b5ec
FG
380 ty::Adt(def, args) => {
381 assert!(!def.is_union()); // Valtree construction would never succeed for unions.
382 PatKind::Leaf {
383 subpatterns: self.field_pats(
384 cv.unwrap_branch().iter().copied().zip(
385 def.non_enum_variant()
386 .fields
387 .iter()
388 .map(|field| field.ty(self.tcx(), args)),
389 ),
390 )?,
391 }
392 }
fe692bf9
FG
393 ty::Slice(elem_ty) => PatKind::Slice {
394 prefix: cv
395 .unwrap_branch()
396 .iter()
397 .map(|val| self.recur(*val, *elem_ty, false))
398 .collect::<Result<_, _>>()?,
399 slice: None,
400 suffix: Box::new([]),
401 },
402 ty::Array(elem_ty, _) => PatKind::Array {
403 prefix: cv
404 .unwrap_branch()
1b1a35ee 405 .iter()
fe692bf9 406 .map(|val| self.recur(*val, *elem_ty, false))
1b1a35ee
XL
407 .collect::<Result<_, _>>()?,
408 slice: None,
f2b60f7d 409 suffix: Box::new([]),
1b1a35ee
XL
410 },
411 ty::Ref(_, pointee_ty, ..) => match *pointee_ty.kind() {
fe692bf9 412 // `&str` is represented as a valtree, let's keep using this
1b1a35ee 413 // optimization for now.
781aab86
FG
414 ty::Str => {
415 PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) }
416 }
49aad941
FG
417 // Backwards compatibility hack: support references to non-structural types,
418 // but hard error if we aren't behind a double reference. We could just use
419 // the fallback code path below, but that would allow *more* of this fishy
420 // code to compile, as then it only goes through the future incompat lint
421 // instead of a hard error.
9c376795 422 ty::Adt(_, _) if !self.type_marked_structural(*pointee_ty) => {
1b1a35ee 423 if self.behind_reference.get() {
ed00b5ec
FG
424 if self.saw_const_match_error.get().is_none()
425 && !self.saw_const_match_lint.get()
426 {
fe692bf9
FG
427 self.saw_const_match_lint.set(true);
428 tcx.emit_spanned_lint(
1b1a35ee
XL
429 lint::builtin::INDIRECT_STRUCTURAL_MATCH,
430 self.id,
9c376795
FG
431 span,
432 IndirectStructuralMatch { non_sm_ty: *pointee_ty },
1b1a35ee
XL
433 );
434 }
781aab86 435 return Err(FallbackToOpaqueConst);
1b1a35ee 436 } else {
ed00b5ec
FG
437 if let Some(e) = self.saw_const_match_error.get() {
438 // We already errored. Signal that in the pattern, so that follow up errors can be silenced.
439 PatKind::Error(e)
440 } else {
9c376795 441 let err = TypeNotStructural { span, non_sm_ty: *pointee_ty };
ed00b5ec
FG
442 let e = tcx.sess.emit_err(err);
443 self.saw_const_match_error.set(Some(e));
444 // We errored. Signal that in the pattern, so that follow up errors can be silenced.
445 PatKind::Error(e)
1b1a35ee 446 }
1b1a35ee
XL
447 }
448 }
449 // All other references are converted into deref patterns and then recursively
450 // convert the dereferenced constant to a pattern that is the sub-pattern of the
451 // deref pattern.
452 _ => {
fe692bf9 453 if !pointee_ty.is_sized(tcx, param_env) && !pointee_ty.is_slice() {
9c376795 454 let err = UnsizedPattern { span, non_sm_ty: *pointee_ty };
ed00b5ec
FG
455 let e = tcx.sess.emit_err(err);
456 // We errored. Signal that in the pattern, so that follow up errors can be silenced.
457 PatKind::Error(e)
136023e0
XL
458 } else {
459 let old = self.behind_reference.replace(true);
fe692bf9
FG
460 // `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when
461 // matching against references, you can only use byte string literals.
462 // The typechecker has a special case for byte string literals, by treating them
463 // as slices. This means we turn `&[T; N]` constants into slice patterns, which
464 // has no negative effects on pattern matching, even if we're actually matching on
465 // arrays.
466 let pointee_ty = match *pointee_ty.kind() {
467 ty::Array(elem_ty, _) if self.treat_byte_string_as_slice => {
468 Ty::new_slice(tcx, elem_ty)
469 }
470 _ => *pointee_ty,
471 };
472 // References have the same valtree representation as their pointee.
473 let subpattern = self.recur(cv, pointee_ty, false)?;
136023e0 474 self.behind_reference.set(old);
49aad941 475 PatKind::Deref { subpattern }
136023e0 476 }
1b1a35ee
XL
477 }
478 },
ed00b5ec
FG
479 ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => {
480 // The raw pointers we see here have been "vetted" by valtree construction to be
481 // just integers, so we simply allow them.
781aab86
FG
482 PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) }
483 }
ed00b5ec
FG
484 ty::FnPtr(..) => {
485 // Valtree construction would never succeed for these, so this is unreachable.
486 unreachable!()
487 }
1b1a35ee 488 _ => {
fe692bf9 489 let err = InvalidPattern { span, non_sm_ty: ty };
ed00b5ec
FG
490 let e = tcx.sess.emit_err(err);
491 self.saw_const_match_error.set(Some(e));
492 // We errored. Signal that in the pattern, so that follow up errors can be silenced.
493 PatKind::Error(e)
1b1a35ee
XL
494 }
495 };
496
ed00b5ec 497 if self.saw_const_match_error.get().is_none()
1b1a35ee
XL
498 && !self.saw_const_match_lint.get()
499 && mir_structural_match_violation
500 // FIXME(#73448): Find a way to bring const qualification into parity with
501 // `search_for_structural_match_violation` and then remove this condition.
9c376795 502
1b1a35ee
XL
503 // Obtain the actual type that isn't annotated. If we just looked at `cv.ty` we
504 // could get `Option<NonStructEq>`, even though `Option` is annotated with derive.
fe692bf9 505 && let Some(non_sm_ty) = traits::search_for_structural_match_violation(span, tcx, ty)
9c376795
FG
506 {
507 self.saw_const_match_lint.set(true);
508 tcx.emit_spanned_lint(
1b1a35ee
XL
509 lint::builtin::NONTRIVIAL_STRUCTURAL_MATCH,
510 id,
511 span,
ed00b5ec 512 NontrivialStructuralMatch { non_sm_ty },
1b1a35ee
XL
513 );
514 }
515
fe692bf9 516 Ok(Box::new(Pat { span, ty, kind }))
1b1a35ee
XL
517 }
518}