@@ -7,7 +7,7 @@ use rustc_middle::mir;
77use rustc_middle:: thir:: { FieldPat , Pat , PatKind } ;
88use rustc_middle:: ty:: { self , Ty , TyCtxt , ValTree } ;
99use rustc_session:: lint;
10- use rustc_span:: Span ;
10+ use rustc_span:: { ErrorGuaranteed , Span } ;
1111use rustc_target:: abi:: { FieldIdx , VariantIdx } ;
1212use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt ;
1313use rustc_trait_selection:: traits:: { self , ObligationCause } ;
@@ -48,7 +48,7 @@ struct ConstToPat<'tcx> {
4848 // This tracks if we emitted some hard error for a given const value, so that
4949 // we will not subsequently issue an irrelevant lint for the same const
5050 // value.
51- saw_const_match_error : Cell < bool > ,
51+ saw_const_match_error : Cell < Option < ErrorGuaranteed > > ,
5252
5353 // This tracks if we emitted some diagnostic for a given const value, so that
5454 // we will not subsequently issue an irrelevant lint for the same const
@@ -84,7 +84,7 @@ impl<'tcx> ConstToPat<'tcx> {
8484 span,
8585 infcx,
8686 param_env : pat_ctxt. param_env ,
87- saw_const_match_error : Cell :: new ( false ) ,
87+ saw_const_match_error : Cell :: new ( None ) ,
8888 saw_const_match_lint : Cell :: new ( false ) ,
8989 behind_reference : Cell :: new ( false ) ,
9090 treat_byte_string_as_slice : pat_ctxt
@@ -154,7 +154,7 @@ impl<'tcx> ConstToPat<'tcx> {
154154 } ) ,
155155 } ;
156156
157- if ! self . saw_const_match_error . get ( ) {
157+ if self . saw_const_match_error . get ( ) . is_none ( ) {
158158 // If we were able to successfully convert the const to some pat (possibly with some
159159 // lints, but no errors), double-check that all types in the const implement
160160 // `Structural` and `PartialEq`.
@@ -180,23 +180,26 @@ impl<'tcx> ConstToPat<'tcx> {
180180
181181 if let Some ( non_sm_ty) = structural {
182182 if !self . type_has_partial_eq_impl ( cv. ty ( ) ) {
183- if let ty:: Adt ( def, ..) = non_sm_ty. kind ( ) {
183+ let e = if let ty:: Adt ( def, ..) = non_sm_ty. kind ( ) {
184184 if def. is_union ( ) {
185185 let err = UnionPattern { span : self . span } ;
186- self . tcx ( ) . sess . emit_err ( err) ;
186+ self . tcx ( ) . sess . emit_err ( err)
187187 } else {
188188 // fatal avoids ICE from resolution of nonexistent method (rare case).
189189 self . tcx ( )
190190 . sess
191- . emit_fatal ( TypeNotStructural { span : self . span , non_sm_ty } ) ;
191+ . emit_fatal ( TypeNotStructural { span : self . span , non_sm_ty } )
192192 }
193193 } else {
194194 let err = InvalidPattern { span : self . span , non_sm_ty } ;
195- self . tcx ( ) . sess . emit_err ( err) ;
196- }
195+ self . tcx ( ) . sess . emit_err ( err)
196+ } ;
197197 // All branches above emitted an error. Don't print any more lints.
198- // The pattern we return is irrelevant since we errored.
199- return Box :: new ( Pat { span : self . span , ty : cv. ty ( ) , kind : PatKind :: Wild } ) ;
198+ // We errored. Signal that in the pattern, so that follow up errors can be silenced.
199+ let kind = PatKind :: Constant {
200+ value : mir:: Const :: Ty ( ty:: Const :: new_error ( self . tcx ( ) , e, cv. ty ( ) ) ) ,
201+ } ;
202+ return Box :: new ( Pat { span : self . span , ty : cv. ty ( ) , kind } ) ;
200203 } else if !self . saw_const_match_lint . get ( ) {
201204 if let Some ( mir_structural_match_violation) = mir_structural_match_violation {
202205 match non_sm_ty. kind ( ) {
@@ -330,7 +333,7 @@ impl<'tcx> ConstToPat<'tcx> {
330333 // Backwards compatibility hack because we can't cause hard errors on these
331334 // types, so we compare them via `PartialEq::eq` at runtime.
332335 ty:: Adt ( ..) if !self . type_marked_structural ( ty) && self . behind_reference . get ( ) => {
333- if ! self . saw_const_match_error . get ( ) && !self . saw_const_match_lint . get ( ) {
336+ if self . saw_const_match_error . get ( ) . is_none ( ) && !self . saw_const_match_lint . get ( ) {
334337 self . saw_const_match_lint . set ( true ) ;
335338 tcx. emit_spanned_lint (
336339 lint:: builtin:: INDIRECT_STRUCTURAL_MATCH ,
@@ -345,18 +348,18 @@ impl<'tcx> ConstToPat<'tcx> {
345348 return Err ( FallbackToOpaqueConst ) ;
346349 }
347350 ty:: FnDef ( ..) => {
348- self . saw_const_match_error . set ( true ) ;
349- tcx . sess . emit_err ( InvalidPattern { span , non_sm_ty : ty } ) ;
350- // We errored, so the pattern we generate is irrelevant .
351- PatKind :: Wild
351+ let e = tcx . sess . emit_err ( InvalidPattern { span , non_sm_ty : ty } ) ;
352+ self . saw_const_match_error . set ( Some ( e ) ) ;
353+ // We errored. Signal that in the pattern, so that follow up errors can be silenced .
354+ PatKind :: Constant { value : mir :: Const :: Ty ( ty :: Const :: new_error ( tcx , e , ty ) ) }
352355 }
353356 ty:: Adt ( adt_def, _) if !self . type_marked_structural ( ty) => {
354357 debug ! ( "adt_def {:?} has !type_marked_structural for cv.ty: {:?}" , adt_def, ty, ) ;
355- self . saw_const_match_error . set ( true ) ;
356358 let err = TypeNotStructural { span, non_sm_ty : ty } ;
357- tcx. sess . emit_err ( err) ;
358- // We errored, so the pattern we generate is irrelevant.
359- PatKind :: Wild
359+ let e = tcx. sess . emit_err ( err) ;
360+ self . saw_const_match_error . set ( Some ( e) ) ;
361+ // We errored. Signal that in the pattern, so that follow up errors can be silenced.
362+ PatKind :: Constant { value : mir:: Const :: Ty ( ty:: Const :: new_error ( tcx, e, ty) ) }
360363 }
361364 ty:: Adt ( adt_def, args) if adt_def. is_enum ( ) => {
362365 let ( & variant_index, fields) = cv. unwrap_branch ( ) . split_first ( ) . unwrap ( ) ;
@@ -416,7 +419,9 @@ impl<'tcx> ConstToPat<'tcx> {
416419 // instead of a hard error.
417420 ty:: Adt ( _, _) if !self . type_marked_structural ( * pointee_ty) => {
418421 if self . behind_reference . get ( ) {
419- if !self . saw_const_match_error . get ( ) && !self . saw_const_match_lint . get ( ) {
422+ if self . saw_const_match_error . get ( ) . is_none ( )
423+ && !self . saw_const_match_lint . get ( )
424+ {
420425 self . saw_const_match_lint . set ( true ) ;
421426 tcx. emit_spanned_lint (
422427 lint:: builtin:: INDIRECT_STRUCTURAL_MATCH ,
@@ -427,14 +432,20 @@ impl<'tcx> ConstToPat<'tcx> {
427432 }
428433 return Err ( FallbackToOpaqueConst ) ;
429434 } else {
430- if !self . saw_const_match_error . get ( ) {
431- self . saw_const_match_error . set ( true ) ;
435+ if let Some ( e) = self . saw_const_match_error . get ( ) {
436+ // We already errored. Signal that in the pattern, so that follow up errors can be silenced.
437+ PatKind :: Constant {
438+ value : mir:: Const :: Ty ( ty:: Const :: new_error ( tcx, e, ty) ) ,
439+ }
440+ } else {
432441 let err = TypeNotStructural { span, non_sm_ty : * pointee_ty } ;
433- tcx. sess . emit_err ( err) ;
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 :: Constant {
446+ value : mir:: Const :: Ty ( ty:: Const :: new_error ( tcx, e, ty) ) ,
447+ }
434448 }
435- tcx. sess . delay_span_bug ( span, "`saw_const_match_error` set but no error?" ) ;
436- // We errored, so the pattern we generate is irrelevant.
437- PatKind :: Wild
438449 }
439450 }
440451 // All other references are converted into deref patterns and then recursively
@@ -443,11 +454,11 @@ impl<'tcx> ConstToPat<'tcx> {
443454 _ => {
444455 if !pointee_ty. is_sized ( tcx, param_env) && !pointee_ty. is_slice ( ) {
445456 let err = UnsizedPattern { span, non_sm_ty : * pointee_ty } ;
446- tcx. sess . emit_err ( err) ;
447-
448- // FIXME: introduce PatKind::Error to silence follow up diagnostics due to unreachable patterns.
449- // We errored, so the pattern we generate is irrelevant.
450- PatKind :: Wild
457+ let e = tcx. sess . emit_err ( err) ;
458+ // We errored. Signal that in the pattern, so that follow up errors can be silenced.
459+ PatKind :: Constant {
460+ value : mir :: Const :: Ty ( ty :: Const :: new_error ( tcx , e , ty ) ) ,
461+ }
451462 } else {
452463 let old = self . behind_reference . replace ( true ) ;
453464 // `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when
@@ -474,15 +485,15 @@ impl<'tcx> ConstToPat<'tcx> {
474485 }
475486 ty:: FnPtr ( ..) | ty:: RawPtr ( ..) => unreachable ! ( ) ,
476487 _ => {
477- self . saw_const_match_error . set ( true ) ;
478488 let err = InvalidPattern { span, non_sm_ty : ty } ;
479- tcx. sess . emit_err ( err) ;
480- // We errored, so the pattern we generate is irrelevant.
481- PatKind :: Wild
489+ let e = tcx. sess . emit_err ( err) ;
490+ self . saw_const_match_error . set ( Some ( e) ) ;
491+ // We errored. Signal that in the pattern, so that follow up errors can be silenced.
492+ PatKind :: Constant { value : mir:: Const :: Ty ( ty:: Const :: new_error ( tcx, e, ty) ) }
482493 }
483494 } ;
484495
485- if ! self . saw_const_match_error . get ( )
496+ if self . saw_const_match_error . get ( ) . is_none ( )
486497 && !self . saw_const_match_lint . get ( )
487498 && mir_structural_match_violation
488499 // FIXME(#73448): Find a way to bring const qualification into parity with
0 commit comments