@@ -450,7 +450,20 @@ pub enum Diverges {
450
450
451
451
/// Definitely known to diverge and therefore
452
452
/// not reach the next sibling or its parent.
453
- Always ,
453
+ Always {
454
+ /// The `Span` points to the expression
455
+ /// that caused us to diverge
456
+ /// (e.g. `return`, `break`, etc).
457
+ span : Span ,
458
+ /// In some cases (e.g. a `match` expression
459
+ /// where all arms diverge), we may be
460
+ /// able to provide a more informative
461
+ /// message to the user.
462
+ /// If this is `None`, a default messsage
463
+ /// will be generated, which is suitable
464
+ /// for most cases.
465
+ custom_note : Option < & ' static str >
466
+ } ,
454
467
455
468
/// Same as `Always` but with a reachability
456
469
/// warning already emitted.
@@ -486,8 +499,22 @@ impl ops::BitOrAssign for Diverges {
486
499
}
487
500
488
501
impl Diverges {
489
- fn always ( self ) -> bool {
490
- self >= Diverges :: Always
502
+ /// Creates a `Diverges::Always` with the provided `span` and the default note message.
503
+ fn always ( span : Span ) -> Diverges {
504
+ Diverges :: Always {
505
+ span,
506
+ custom_note : None
507
+ }
508
+ }
509
+
510
+ fn is_always ( self ) -> bool {
511
+ // Enum comparison ignores the
512
+ // contents of fields, so we just
513
+ // fill them in with garbage here.
514
+ self >= Diverges :: Always {
515
+ span : DUMMY_SP ,
516
+ custom_note : None
517
+ }
491
518
}
492
519
}
493
520
@@ -2307,17 +2334,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2307
2334
/// Produces warning on the given node, if the current point in the
2308
2335
/// function is unreachable, and there hasn't been another warning.
2309
2336
fn warn_if_unreachable ( & self , id : hir:: HirId , span : Span , kind : & str ) {
2310
- if self . diverges . get ( ) == Diverges :: Always &&
2337
+ // FIXME: Combine these two 'if' expressions into one once
2338
+ // let chains are implemented
2339
+ if let Diverges :: Always { span : orig_span, custom_note } = self . diverges . get ( ) {
2311
2340
// If span arose from a desugaring of `if` or `while`, then it is the condition itself,
2312
2341
// which diverges, that we are about to lint on. This gives suboptimal diagnostics.
2313
2342
// Instead, stop here so that the `if`- or `while`-expression's block is linted instead.
2314
- !span. is_desugaring ( DesugaringKind :: CondTemporary ) {
2315
- self . diverges . set ( Diverges :: WarnedAlways ) ;
2343
+ if !span. is_desugaring ( DesugaringKind :: CondTemporary ) {
2344
+ self . diverges . set ( Diverges :: WarnedAlways ) ;
2316
2345
2317
- debug ! ( "warn_if_unreachable: id={:?} span={:?} kind={}" , id, span, kind) ;
2346
+ debug ! ( "warn_if_unreachable: id={:?} span={:?} kind={}" , id, span, kind) ;
2318
2347
2319
- let msg = format ! ( "unreachable {}" , kind) ;
2320
- self . tcx ( ) . lint_hir ( lint:: builtin:: UNREACHABLE_CODE , id, span, & msg) ;
2348
+ let msg = format ! ( "unreachable {}" , kind) ;
2349
+ self . tcx ( ) . struct_span_lint_hir ( lint:: builtin:: UNREACHABLE_CODE , id, span, & msg)
2350
+ . span_note (
2351
+ orig_span,
2352
+ custom_note. unwrap_or ( "any code following this expression is unreachable" )
2353
+ )
2354
+ . emit ( ) ;
2355
+ }
2321
2356
}
2322
2357
}
2323
2358
@@ -3825,7 +3860,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
3825
3860
//
3826
3861
// #41425 -- label the implicit `()` as being the
3827
3862
// "found type" here, rather than the "expected type".
3828
- if !self . diverges . get ( ) . always ( ) {
3863
+ if !self . diverges . get ( ) . is_always ( ) {
3829
3864
// #50009 -- Do not point at the entire fn block span, point at the return type
3830
3865
// span, as it is the cause of the requirement, and
3831
3866
// `consider_hint_about_removing_semicolon` will point at the last expression
0 commit comments