@@ -450,7 +450,20 @@ pub enum Diverges {
450450
451451 /// Definitely known to diverge and therefore
452452 /// 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+ } ,
454467
455468 /// Same as `Always` but with a reachability
456469 /// warning already emitted.
@@ -486,8 +499,22 @@ impl ops::BitOrAssign for Diverges {
486499}
487500
488501impl 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+ }
491518 }
492519}
493520
@@ -2307,17 +2334,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
23072334 /// Produces warning on the given node, if the current point in the
23082335 /// function is unreachable, and there hasn't been another warning.
23092336 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 ( ) {
23112340 // If span arose from a desugaring of `if` or `while`, then it is the condition itself,
23122341 // which diverges, that we are about to lint on. This gives suboptimal diagnostics.
23132342 // 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 ) ;
23162345
2317- debug ! ( "warn_if_unreachable: id={:?} span={:?} kind={}" , id, span, kind) ;
2346+ debug ! ( "warn_if_unreachable: id={:?} span={:?} kind={}" , id, span, kind) ;
23182347
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+ }
23212356 }
23222357 }
23232358
@@ -3825,7 +3860,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
38253860 //
38263861 // #41425 -- label the implicit `()` as being the
38273862 // "found type" here, rather than the "expected type".
3828- if !self . diverges . get ( ) . always ( ) {
3863+ if !self . diverges . get ( ) . is_always ( ) {
38293864 // #50009 -- Do not point at the entire fn block span, point at the return type
38303865 // span, as it is the cause of the requirement, and
38313866 // `consider_hint_about_removing_semicolon` will point at the last expression
0 commit comments