@@ -7,7 +7,7 @@ use rustc_middle::mir;
7
7
use rustc_middle:: thir:: { FieldPat , Pat , PatKind } ;
8
8
use rustc_middle:: ty:: { self , Ty , TyCtxt , ValTree } ;
9
9
use rustc_session:: lint;
10
- use rustc_span:: Span ;
10
+ use rustc_span:: { ErrorGuaranteed , Span } ;
11
11
use rustc_target:: abi:: { FieldIdx , VariantIdx } ;
12
12
use rustc_trait_selection:: traits:: query:: evaluate_obligation:: InferCtxtExt ;
13
13
use rustc_trait_selection:: traits:: { self , ObligationCause } ;
@@ -48,7 +48,7 @@ struct ConstToPat<'tcx> {
48
48
// This tracks if we emitted some hard error for a given const value, so that
49
49
// we will not subsequently issue an irrelevant lint for the same const
50
50
// value.
51
- saw_const_match_error : Cell < bool > ,
51
+ saw_const_match_error : Cell < Option < ErrorGuaranteed > > ,
52
52
53
53
// This tracks if we emitted some diagnostic for a given const value, so that
54
54
// we will not subsequently issue an irrelevant lint for the same const
@@ -84,7 +84,7 @@ impl<'tcx> ConstToPat<'tcx> {
84
84
span,
85
85
infcx,
86
86
param_env : pat_ctxt. param_env ,
87
- saw_const_match_error : Cell :: new ( false ) ,
87
+ saw_const_match_error : Cell :: new ( None ) ,
88
88
saw_const_match_lint : Cell :: new ( false ) ,
89
89
behind_reference : Cell :: new ( false ) ,
90
90
treat_byte_string_as_slice : pat_ctxt
@@ -154,7 +154,7 @@ impl<'tcx> ConstToPat<'tcx> {
154
154
} ) ,
155
155
} ;
156
156
157
- if ! self . saw_const_match_error . get ( ) {
157
+ if self . saw_const_match_error . get ( ) . is_none ( ) {
158
158
// If we were able to successfully convert the const to some pat (possibly with some
159
159
// lints, but no errors), double-check that all types in the const implement
160
160
// `Structural` and `PartialEq`.
@@ -180,23 +180,26 @@ impl<'tcx> ConstToPat<'tcx> {
180
180
181
181
if let Some ( non_sm_ty) = structural {
182
182
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 ( ) {
184
184
if def. is_union ( ) {
185
185
let err = UnionPattern { span : self . span } ;
186
- self . tcx ( ) . sess . emit_err ( err) ;
186
+ self . tcx ( ) . sess . emit_err ( err)
187
187
} else {
188
188
// fatal avoids ICE from resolution of nonexistent method (rare case).
189
189
self . tcx ( )
190
190
. sess
191
- . emit_fatal ( TypeNotStructural { span : self . span , non_sm_ty } ) ;
191
+ . emit_fatal ( TypeNotStructural { span : self . span , non_sm_ty } )
192
192
}
193
193
} else {
194
194
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
+ } ;
197
197
// 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 } ) ;
200
203
} else if !self . saw_const_match_lint . get ( ) {
201
204
if let Some ( mir_structural_match_violation) = mir_structural_match_violation {
202
205
match non_sm_ty. kind ( ) {
@@ -330,7 +333,7 @@ impl<'tcx> ConstToPat<'tcx> {
330
333
// Backwards compatibility hack because we can't cause hard errors on these
331
334
// types, so we compare them via `PartialEq::eq` at runtime.
332
335
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 ( ) {
334
337
self . saw_const_match_lint . set ( true ) ;
335
338
tcx. emit_spanned_lint (
336
339
lint:: builtin:: INDIRECT_STRUCTURAL_MATCH ,
@@ -345,18 +348,18 @@ impl<'tcx> ConstToPat<'tcx> {
345
348
return Err ( FallbackToOpaqueConst ) ;
346
349
}
347
350
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 ) ) }
352
355
}
353
356
ty:: Adt ( adt_def, _) if !self . type_marked_structural ( ty) => {
354
357
debug ! ( "adt_def {:?} has !type_marked_structural for cv.ty: {:?}" , adt_def, ty, ) ;
355
- self . saw_const_match_error . set ( true ) ;
356
358
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) ) }
360
363
}
361
364
ty:: Adt ( adt_def, args) if adt_def. is_enum ( ) => {
362
365
let ( & variant_index, fields) = cv. unwrap_branch ( ) . split_first ( ) . unwrap ( ) ;
@@ -416,7 +419,9 @@ impl<'tcx> ConstToPat<'tcx> {
416
419
// instead of a hard error.
417
420
ty:: Adt ( _, _) if !self . type_marked_structural ( * pointee_ty) => {
418
421
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
+ {
420
425
self . saw_const_match_lint . set ( true ) ;
421
426
tcx. emit_spanned_lint (
422
427
lint:: builtin:: INDIRECT_STRUCTURAL_MATCH ,
@@ -427,14 +432,20 @@ impl<'tcx> ConstToPat<'tcx> {
427
432
}
428
433
return Err ( FallbackToOpaqueConst ) ;
429
434
} 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 {
432
441
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
+ }
434
448
}
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
438
449
}
439
450
}
440
451
// All other references are converted into deref patterns and then recursively
@@ -443,11 +454,11 @@ impl<'tcx> ConstToPat<'tcx> {
443
454
_ => {
444
455
if !pointee_ty. is_sized ( tcx, param_env) && !pointee_ty. is_slice ( ) {
445
456
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
+ }
451
462
} else {
452
463
let old = self . behind_reference . replace ( true ) ;
453
464
// `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when
@@ -474,15 +485,15 @@ impl<'tcx> ConstToPat<'tcx> {
474
485
}
475
486
ty:: FnPtr ( ..) | ty:: RawPtr ( ..) => unreachable ! ( ) ,
476
487
_ => {
477
- self . saw_const_match_error . set ( true ) ;
478
488
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) ) }
482
493
}
483
494
} ;
484
495
485
- if ! self . saw_const_match_error . get ( )
496
+ if self . saw_const_match_error . get ( ) . is_none ( )
486
497
&& !self . saw_const_match_lint . get ( )
487
498
&& mir_structural_match_violation
488
499
// FIXME(#73448): Find a way to bring const qualification into parity with
0 commit comments