From 822393d690eb7c238c18c1bb0b1e7831c4776cd3 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 18 Sep 2019 18:22:13 -0400 Subject: [PATCH 1/8] Point at original span when emitting unreachable lint Fixes #64590 When we emit an 'unreachable' lint, we now add a note pointing at the expression that actually causes the code to be unreachable (e.g. `return`, `break`, `panic`). This is especially useful when macros are involved, since a diverging expression might be hidden inside of a macro invocation. --- src/librustc_typeck/check/_match.rs | 4 +-- src/librustc_typeck/check/expr.rs | 2 +- src/librustc_typeck/check/mod.rs | 25 +++++++++++++------ src/test/ui/dead-code-ret.stderr | 5 ++++ src/test/ui/if-ret.stderr | 5 ++++ src/test/ui/issues/issue-2150.stderr | 6 +++++ src/test/ui/issues/issue-7246.stderr | 5 ++++ .../ui/lint/lint-attr-non-item-node.stderr | 5 ++++ src/test/ui/liveness/liveness-unused.stderr | 5 ++++ .../match-no-arms-unreachable-after.stderr | 5 ++++ src/test/ui/never-assign-dead-code.stderr | 12 +++++++++ src/test/ui/reachable/expr_add.stderr | 5 ++++ src/test/ui/reachable/expr_again.stderr | 5 ++++ src/test/ui/reachable/expr_array.stderr | 11 ++++++++ src/test/ui/reachable/expr_assign.stderr | 17 +++++++++++++ src/test/ui/reachable/expr_block.stderr | 10 ++++++++ src/test/ui/reachable/expr_box.stderr | 5 ++++ src/test/ui/reachable/expr_call.stderr | 11 ++++++++ src/test/ui/reachable/expr_cast.stderr | 5 ++++ src/test/ui/reachable/expr_if.stderr | 10 ++++++++ src/test/ui/reachable/expr_loop.stderr | 15 +++++++++++ src/test/ui/reachable/expr_match.stderr | 10 ++++++++ src/test/ui/reachable/expr_method.stderr | 11 ++++++++ src/test/ui/reachable/expr_repeat.stderr | 5 ++++ src/test/ui/reachable/expr_return.stderr | 5 ++++ src/test/ui/reachable/expr_return_in_macro.rs | 15 +++++++++++ .../ui/reachable/expr_return_in_macro.stderr | 22 ++++++++++++++++ src/test/ui/reachable/expr_struct.stderr | 23 +++++++++++++++++ src/test/ui/reachable/expr_tup.stderr | 11 ++++++++ src/test/ui/reachable/expr_type.stderr | 5 ++++ src/test/ui/reachable/expr_unary.stderr | 5 ++++ src/test/ui/reachable/expr_while.stderr | 11 ++++++++ .../protect-precedences.stderr | 5 ++++ .../ui/unreachable/unreachable-code.stderr | 5 ++++ .../ui/unreachable/unreachable-in-call.stderr | 11 ++++++++ .../unreachable-try-pattern.stderr | 5 ++++ .../unwarned-match-on-never.stderr | 17 +++++++++++++ 37 files changed, 328 insertions(+), 11 deletions(-) create mode 100644 src/test/ui/reachable/expr_return_in_macro.rs create mode 100644 src/test/ui/reachable/expr_return_in_macro.stderr diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 308a3d8ebc2..a1c937b95ba 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -43,7 +43,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If there are no arms, that is a diverging match; a special case. if arms.is_empty() { - self.diverges.set(self.diverges.get() | Diverges::Always); + self.diverges.set(self.diverges.get() | Diverges::Always(expr.span)); return tcx.types.never; } @@ -69,7 +69,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // warnings). match all_pats_diverge { Diverges::Maybe => Diverges::Maybe, - Diverges::Always | Diverges::WarnedAlways => Diverges::WarnedAlways, + Diverges::Always(..) | Diverges::WarnedAlways => Diverges::WarnedAlways, } }).collect(); diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 56bd903040a..3ba453748ff 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -170,7 +170,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Any expression that produces a value of type `!` must have diverged if ty.is_never() { - self.diverges.set(self.diverges.get() | Diverges::Always); + self.diverges.set(self.diverges.get() | Diverges::Always(expr.span)); } // Record the type, which applies it effects. diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 1197160fa95..0fced373946 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -450,7 +450,10 @@ pub enum Diverges { /// Definitely known to diverge and therefore /// not reach the next sibling or its parent. - Always, + /// The `Span` points to the expression + /// that caused us to diverge + /// (e.g. `return`, `break`, etc) + Always(Span), /// Same as `Always` but with a reachability /// warning already emitted. @@ -487,7 +490,7 @@ impl ops::BitOrAssign for Diverges { impl Diverges { fn always(self) -> bool { - self >= Diverges::Always + self >= Diverges::Always(DUMMY_SP) } } @@ -2307,17 +2310,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Produces warning on the given node, if the current point in the /// function is unreachable, and there hasn't been another warning. fn warn_if_unreachable(&self, id: hir::HirId, span: Span, kind: &str) { - if self.diverges.get() == Diverges::Always && + // FIXME: Combine these two 'if' expressions into one once + // let chains are implemented + if let Diverges::Always(orig_span) = self.diverges.get() { // If span arose from a desugaring of `if` or `while`, then it is the condition itself, // which diverges, that we are about to lint on. This gives suboptimal diagnostics. // Instead, stop here so that the `if`- or `while`-expression's block is linted instead. - !span.is_desugaring(DesugaringKind::CondTemporary) { - self.diverges.set(Diverges::WarnedAlways); + if !span.is_desugaring(DesugaringKind::CondTemporary) { + self.diverges.set(Diverges::WarnedAlways); - debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind); + debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind); - let msg = format!("unreachable {}", kind); - self.tcx().lint_hir(lint::builtin::UNREACHABLE_CODE, id, span, &msg); + let msg = format!("unreachable {}", kind); + let mut err = self.tcx().struct_span_lint_hir(lint::builtin::UNREACHABLE_CODE, + id, span, &msg); + err.span_note(orig_span, "any code following this expression is unreachable"); + err.emit(); + } } } diff --git a/src/test/ui/dead-code-ret.stderr b/src/test/ui/dead-code-ret.stderr index 092a176f443..0ce31ea40dd 100644 --- a/src/test/ui/dead-code-ret.stderr +++ b/src/test/ui/dead-code-ret.stderr @@ -9,6 +9,11 @@ note: lint level defined here | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ +note: any code following this expression is unreachable + --> $DIR/dead-code-ret.rs:6:5 + | +LL | return; + | ^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/if-ret.stderr b/src/test/ui/if-ret.stderr index 73402e55a4f..2df8f22944e 100644 --- a/src/test/ui/if-ret.stderr +++ b/src/test/ui/if-ret.stderr @@ -5,4 +5,9 @@ LL | fn foo() { if (return) { } } | ^^^ | = note: `#[warn(unreachable_code)]` on by default +note: any code following this expression is unreachable + --> $DIR/if-ret.rs:6:15 + | +LL | fn foo() { if (return) { } } + | ^^^^^^^^ diff --git a/src/test/ui/issues/issue-2150.stderr b/src/test/ui/issues/issue-2150.stderr index 59000f3dd53..623f098d0b3 100644 --- a/src/test/ui/issues/issue-2150.stderr +++ b/src/test/ui/issues/issue-2150.stderr @@ -9,6 +9,12 @@ note: lint level defined here | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ +note: any code following this expression is unreachable + --> $DIR/issue-2150.rs:7:5 + | +LL | panic!(); + | ^^^^^^^^^ + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/issues/issue-7246.stderr b/src/test/ui/issues/issue-7246.stderr index e049295e913..d1b23672dc7 100644 --- a/src/test/ui/issues/issue-7246.stderr +++ b/src/test/ui/issues/issue-7246.stderr @@ -9,6 +9,11 @@ note: lint level defined here | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ +note: any code following this expression is unreachable + --> $DIR/issue-7246.rs:6:5 + | +LL | return; + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/lint/lint-attr-non-item-node.stderr b/src/test/ui/lint/lint-attr-non-item-node.stderr index 6eb72c098df..e6c76c24c91 100644 --- a/src/test/ui/lint/lint-attr-non-item-node.stderr +++ b/src/test/ui/lint/lint-attr-non-item-node.stderr @@ -9,6 +9,11 @@ note: lint level defined here | LL | #[deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ +note: any code following this expression is unreachable + --> $DIR/lint-attr-non-item-node.rs:6:9 + | +LL | break; + | ^^^^^ error: aborting due to previous error diff --git a/src/test/ui/liveness/liveness-unused.stderr b/src/test/ui/liveness/liveness-unused.stderr index 40a677c08f2..84e9b5bab99 100644 --- a/src/test/ui/liveness/liveness-unused.stderr +++ b/src/test/ui/liveness/liveness-unused.stderr @@ -10,6 +10,11 @@ note: lint level defined here LL | #![warn(unused)] | ^^^^^^ = note: `#[warn(unreachable_code)]` implied by `#[warn(unused)]` +note: any code following this expression is unreachable + --> $DIR/liveness-unused.rs:91:9 + | +LL | continue; + | ^^^^^^^^ error: unused variable: `x` --> $DIR/liveness-unused.rs:8:7 diff --git a/src/test/ui/match/match-no-arms-unreachable-after.stderr b/src/test/ui/match/match-no-arms-unreachable-after.stderr index 65dcc6ee465..6c46b2473cc 100644 --- a/src/test/ui/match/match-no-arms-unreachable-after.stderr +++ b/src/test/ui/match/match-no-arms-unreachable-after.stderr @@ -9,6 +9,11 @@ note: lint level defined here | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ +note: any code following this expression is unreachable + --> $DIR/match-no-arms-unreachable-after.rs:7:5 + | +LL | match v { } + | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/never-assign-dead-code.stderr b/src/test/ui/never-assign-dead-code.stderr index b1b5bf03fe5..436c703e4b6 100644 --- a/src/test/ui/never-assign-dead-code.stderr +++ b/src/test/ui/never-assign-dead-code.stderr @@ -10,12 +10,24 @@ note: lint level defined here LL | #![warn(unused)] | ^^^^^^ = note: `#[warn(unreachable_code)]` implied by `#[warn(unused)]` +note: any code following this expression is unreachable + --> $DIR/never-assign-dead-code.rs:9:16 + | +LL | let x: ! = panic!("aah"); + | ^^^^^^^^^^^^^ + = note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) warning: unreachable call --> $DIR/never-assign-dead-code.rs:10:5 | LL | drop(x); | ^^^^ + | +note: any code following this expression is unreachable + --> $DIR/never-assign-dead-code.rs:10:10 + | +LL | drop(x); + | ^ warning: unused variable: `x` --> $DIR/never-assign-dead-code.rs:9:9 diff --git a/src/test/ui/reachable/expr_add.stderr b/src/test/ui/reachable/expr_add.stderr index 02b29021cb6..47b4e467abe 100644 --- a/src/test/ui/reachable/expr_add.stderr +++ b/src/test/ui/reachable/expr_add.stderr @@ -9,6 +9,11 @@ note: lint level defined here | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ +note: any code following this expression is unreachable + --> $DIR/expr_add.rs:17:19 + | +LL | let x = Foo + return; + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/reachable/expr_again.stderr b/src/test/ui/reachable/expr_again.stderr index bdc3d143ea5..8e246d940fd 100644 --- a/src/test/ui/reachable/expr_again.stderr +++ b/src/test/ui/reachable/expr_again.stderr @@ -9,6 +9,11 @@ note: lint level defined here | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ +note: any code following this expression is unreachable + --> $DIR/expr_again.rs:7:9 + | +LL | continue; + | ^^^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/reachable/expr_array.stderr b/src/test/ui/reachable/expr_array.stderr index 18d7ffe74bd..419a332e632 100644 --- a/src/test/ui/reachable/expr_array.stderr +++ b/src/test/ui/reachable/expr_array.stderr @@ -9,12 +9,23 @@ note: lint level defined here | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ +note: any code following this expression is unreachable + --> $DIR/expr_array.rs:9:26 + | +LL | let x: [usize; 2] = [return, 22]; + | ^^^^^^ error: unreachable expression --> $DIR/expr_array.rs:14:25 | LL | let x: [usize; 2] = [22, return]; | ^^^^^^^^^^^^ + | +note: any code following this expression is unreachable + --> $DIR/expr_array.rs:14:30 + | +LL | let x: [usize; 2] = [22, return]; + | ^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/reachable/expr_assign.stderr b/src/test/ui/reachable/expr_assign.stderr index def16d90a74..7388fb4a6b9 100644 --- a/src/test/ui/reachable/expr_assign.stderr +++ b/src/test/ui/reachable/expr_assign.stderr @@ -9,18 +9,35 @@ note: lint level defined here | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ +note: any code following this expression is unreachable + --> $DIR/expr_assign.rs:10:9 + | +LL | x = return; + | ^^^^^^ error: unreachable expression --> $DIR/expr_assign.rs:20:14 | LL | *p = return; | ^^^^^^ + | +note: any code following this expression is unreachable + --> $DIR/expr_assign.rs:20:9 + | +LL | *p = return; + | ^^ error: unreachable expression --> $DIR/expr_assign.rs:26:15 | LL | *{return; &mut i} = 22; | ^^^^^^ + | +note: any code following this expression is unreachable + --> $DIR/expr_assign.rs:26:7 + | +LL | *{return; &mut i} = 22; + | ^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/reachable/expr_block.stderr b/src/test/ui/reachable/expr_block.stderr index a498502e6cb..03a6139d688 100644 --- a/src/test/ui/reachable/expr_block.stderr +++ b/src/test/ui/reachable/expr_block.stderr @@ -9,6 +9,11 @@ note: lint level defined here | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ +note: any code following this expression is unreachable + --> $DIR/expr_block.rs:9:9 + | +LL | return; + | ^^^^^^ error: unreachable statement --> $DIR/expr_block.rs:25:9 @@ -16,6 +21,11 @@ error: unreachable statement LL | println!("foo"); | ^^^^^^^^^^^^^^^^ | +note: any code following this expression is unreachable + --> $DIR/expr_block.rs:24:9 + | +LL | return; + | ^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/src/test/ui/reachable/expr_box.stderr b/src/test/ui/reachable/expr_box.stderr index 63137ce3da1..d0f666d2be4 100644 --- a/src/test/ui/reachable/expr_box.stderr +++ b/src/test/ui/reachable/expr_box.stderr @@ -9,6 +9,11 @@ note: lint level defined here | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ +note: any code following this expression is unreachable + --> $DIR/expr_box.rs:6:17 + | +LL | let x = box return; + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/reachable/expr_call.stderr b/src/test/ui/reachable/expr_call.stderr index f2db17e4dfe..3fcea90e7cd 100644 --- a/src/test/ui/reachable/expr_call.stderr +++ b/src/test/ui/reachable/expr_call.stderr @@ -9,12 +9,23 @@ note: lint level defined here | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ +note: any code following this expression is unreachable + --> $DIR/expr_call.rs:13:9 + | +LL | foo(return, 22); + | ^^^^^^ error: unreachable call --> $DIR/expr_call.rs:18:5 | LL | bar(return); | ^^^ + | +note: any code following this expression is unreachable + --> $DIR/expr_call.rs:18:9 + | +LL | bar(return); + | ^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/reachable/expr_cast.stderr b/src/test/ui/reachable/expr_cast.stderr index 3086745d28e..d3ce0ca079f 100644 --- a/src/test/ui/reachable/expr_cast.stderr +++ b/src/test/ui/reachable/expr_cast.stderr @@ -9,6 +9,11 @@ note: lint level defined here | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ +note: any code following this expression is unreachable + --> $DIR/expr_cast.rs:9:14 + | +LL | let x = {return} as !; + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/reachable/expr_if.stderr b/src/test/ui/reachable/expr_if.stderr index f1690e595e5..03284576086 100644 --- a/src/test/ui/reachable/expr_if.stderr +++ b/src/test/ui/reachable/expr_if.stderr @@ -12,6 +12,11 @@ note: lint level defined here | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ +note: any code following this expression is unreachable + --> $DIR/expr_if.rs:7:9 + | +LL | if {return} { + | ^^^^^^ error: unreachable statement --> $DIR/expr_if.rs:27:5 @@ -19,6 +24,11 @@ error: unreachable statement LL | println!("But I am."); | ^^^^^^^^^^^^^^^^^^^^^^ | +note: any code following this expression is unreachable + --> $DIR/expr_if.rs:21:9 + | +LL | return; + | ^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/src/test/ui/reachable/expr_loop.stderr b/src/test/ui/reachable/expr_loop.stderr index 4d3e06c93a3..a4cf8cfcfd9 100644 --- a/src/test/ui/reachable/expr_loop.stderr +++ b/src/test/ui/reachable/expr_loop.stderr @@ -9,6 +9,11 @@ note: lint level defined here | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ +note: any code following this expression is unreachable + --> $DIR/expr_loop.rs:7:12 + | +LL | loop { return; } + | ^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: unreachable statement @@ -17,6 +22,11 @@ error: unreachable statement LL | println!("I am dead."); | ^^^^^^^^^^^^^^^^^^^^^^^ | +note: any code following this expression is unreachable + --> $DIR/expr_loop.rs:20:12 + | +LL | loop { return; } + | ^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: unreachable statement @@ -25,6 +35,11 @@ error: unreachable statement LL | println!("I am dead."); | ^^^^^^^^^^^^^^^^^^^^^^^ | +note: any code following this expression is unreachable + --> $DIR/expr_loop.rs:31:5 + | +LL | loop { 'middle: loop { loop { break 'middle; } } } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: aborting due to 3 previous errors diff --git a/src/test/ui/reachable/expr_match.stderr b/src/test/ui/reachable/expr_match.stderr index 1aef06aec5b..b846b92dcec 100644 --- a/src/test/ui/reachable/expr_match.stderr +++ b/src/test/ui/reachable/expr_match.stderr @@ -9,6 +9,11 @@ note: lint level defined here | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ +note: any code following this expression is unreachable + --> $DIR/expr_match.rs:7:22 + | +LL | match () { () => return } + | ^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: unreachable statement @@ -17,6 +22,11 @@ error: unreachable statement LL | println!("I am dead"); | ^^^^^^^^^^^^^^^^^^^^^^ | +note: any code following this expression is unreachable + --> $DIR/expr_match.rs:18:31 + | +LL | match () { () if false => return, () => return } + | ^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/src/test/ui/reachable/expr_method.stderr b/src/test/ui/reachable/expr_method.stderr index 947ea0fee88..7ad279c9f48 100644 --- a/src/test/ui/reachable/expr_method.stderr +++ b/src/test/ui/reachable/expr_method.stderr @@ -9,12 +9,23 @@ note: lint level defined here | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ +note: any code following this expression is unreachable + --> $DIR/expr_method.rs:16:13 + | +LL | Foo.foo(return, 22); + | ^^^^^^ error: unreachable call --> $DIR/expr_method.rs:21:9 | LL | Foo.bar(return); | ^^^ + | +note: any code following this expression is unreachable + --> $DIR/expr_method.rs:21:13 + | +LL | Foo.bar(return); + | ^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/reachable/expr_repeat.stderr b/src/test/ui/reachable/expr_repeat.stderr index 0536cdef721..3ff6be76dae 100644 --- a/src/test/ui/reachable/expr_repeat.stderr +++ b/src/test/ui/reachable/expr_repeat.stderr @@ -9,6 +9,11 @@ note: lint level defined here | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ +note: any code following this expression is unreachable + --> $DIR/expr_repeat.rs:9:26 + | +LL | let x: [usize; 2] = [return; 2]; + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/reachable/expr_return.stderr b/src/test/ui/reachable/expr_return.stderr index 3317da58aba..31f7ebe7618 100644 --- a/src/test/ui/reachable/expr_return.stderr +++ b/src/test/ui/reachable/expr_return.stderr @@ -9,6 +9,11 @@ note: lint level defined here | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ +note: any code following this expression is unreachable + --> $DIR/expr_return.rs:10:30 + | +LL | let x = {return {return {return;}}}; + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/reachable/expr_return_in_macro.rs b/src/test/ui/reachable/expr_return_in_macro.rs new file mode 100644 index 00000000000..198ede6b141 --- /dev/null +++ b/src/test/ui/reachable/expr_return_in_macro.rs @@ -0,0 +1,15 @@ +// Tests that we generate nice error messages +// when an expression is unreachble due to control +// flow inside of a macro expansion +#![deny(unreachable_code)] + +macro_rules! early_return { + () => { + return () + } +} + +fn main() { + return early_return!(); + //~^ ERROR unreachable expression +} diff --git a/src/test/ui/reachable/expr_return_in_macro.stderr b/src/test/ui/reachable/expr_return_in_macro.stderr new file mode 100644 index 00000000000..ff3abb5551f --- /dev/null +++ b/src/test/ui/reachable/expr_return_in_macro.stderr @@ -0,0 +1,22 @@ +error: unreachable expression + --> $DIR/expr_return_in_macro.rs:13:5 + | +LL | return early_return!(); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/expr_return_in_macro.rs:4:9 + | +LL | #![deny(unreachable_code)] + | ^^^^^^^^^^^^^^^^ +note: any code following this expression is unreachable + --> $DIR/expr_return_in_macro.rs:8:9 + | +LL | return () + | ^^^^^^^^^ +... +LL | return early_return!(); + | --------------- in this macro invocation + +error: aborting due to previous error + diff --git a/src/test/ui/reachable/expr_struct.stderr b/src/test/ui/reachable/expr_struct.stderr index dcccb7a4db3..d08bcc4f0d1 100644 --- a/src/test/ui/reachable/expr_struct.stderr +++ b/src/test/ui/reachable/expr_struct.stderr @@ -9,24 +9,47 @@ note: lint level defined here | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ +note: any code following this expression is unreachable + --> $DIR/expr_struct.rs:14:35 + | +LL | let x = Foo { a: 22, b: 33, ..return }; + | ^^^^^^ error: unreachable expression --> $DIR/expr_struct.rs:19:33 | LL | let x = Foo { a: return, b: 33, ..return }; | ^^ + | +note: any code following this expression is unreachable + --> $DIR/expr_struct.rs:19:22 + | +LL | let x = Foo { a: return, b: 33, ..return }; + | ^^^^^^ error: unreachable expression --> $DIR/expr_struct.rs:24:39 | LL | let x = Foo { a: 22, b: return, ..return }; | ^^^^^^ + | +note: any code following this expression is unreachable + --> $DIR/expr_struct.rs:24:29 + | +LL | let x = Foo { a: 22, b: return, ..return }; + | ^^^^^^ error: unreachable expression --> $DIR/expr_struct.rs:29:13 | LL | let x = Foo { a: 22, b: return }; | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: any code following this expression is unreachable + --> $DIR/expr_struct.rs:29:29 + | +LL | let x = Foo { a: 22, b: return }; + | ^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/reachable/expr_tup.stderr b/src/test/ui/reachable/expr_tup.stderr index 1837031107d..788499533db 100644 --- a/src/test/ui/reachable/expr_tup.stderr +++ b/src/test/ui/reachable/expr_tup.stderr @@ -9,12 +9,23 @@ note: lint level defined here | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ +note: any code following this expression is unreachable + --> $DIR/expr_tup.rs:9:30 + | +LL | let x: (usize, usize) = (return, 2); + | ^^^^^^ error: unreachable expression --> $DIR/expr_tup.rs:14:29 | LL | let x: (usize, usize) = (2, return); | ^^^^^^^^^^^ + | +note: any code following this expression is unreachable + --> $DIR/expr_tup.rs:14:33 + | +LL | let x: (usize, usize) = (2, return); + | ^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/reachable/expr_type.stderr b/src/test/ui/reachable/expr_type.stderr index f867c891634..15eb735da75 100644 --- a/src/test/ui/reachable/expr_type.stderr +++ b/src/test/ui/reachable/expr_type.stderr @@ -9,6 +9,11 @@ note: lint level defined here | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ +note: any code following this expression is unreachable + --> $DIR/expr_type.rs:9:14 + | +LL | let x = {return}: !; + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/reachable/expr_unary.stderr b/src/test/ui/reachable/expr_unary.stderr index 61982289cdc..7f865196166 100644 --- a/src/test/ui/reachable/expr_unary.stderr +++ b/src/test/ui/reachable/expr_unary.stderr @@ -15,6 +15,11 @@ note: lint level defined here | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ +note: any code following this expression is unreachable + --> $DIR/expr_unary.rs:8:20 + | +LL | let x: ! = ! { return; }; + | ^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/reachable/expr_while.stderr b/src/test/ui/reachable/expr_while.stderr index fc528926b4c..b6d6d11ac69 100644 --- a/src/test/ui/reachable/expr_while.stderr +++ b/src/test/ui/reachable/expr_while.stderr @@ -13,6 +13,11 @@ note: lint level defined here | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ +note: any code following this expression is unreachable + --> $DIR/expr_while.rs:7:12 + | +LL | while {return} { + | ^^^^^^ error: unreachable block in `while` expression --> $DIR/expr_while.rs:22:20 @@ -23,6 +28,12 @@ LL | | LL | | println!("I am dead."); LL | | } | |_____^ + | +note: any code following this expression is unreachable + --> $DIR/expr_while.rs:22:12 + | +LL | while {return} { + | ^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/rfc-2497-if-let-chains/protect-precedences.stderr b/src/test/ui/rfc-2497-if-let-chains/protect-precedences.stderr index be7ef658411..ca98a394714 100644 --- a/src/test/ui/rfc-2497-if-let-chains/protect-precedences.stderr +++ b/src/test/ui/rfc-2497-if-let-chains/protect-precedences.stderr @@ -5,4 +5,9 @@ LL | if let _ = return true && false {}; | ^^ | = note: `#[warn(unreachable_code)]` on by default +note: any code following this expression is unreachable + --> $DIR/protect-precedences.rs:13:20 + | +LL | if let _ = return true && false {}; + | ^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/unreachable/unreachable-code.stderr b/src/test/ui/unreachable/unreachable-code.stderr index 803bb966be8..226f088c63a 100644 --- a/src/test/ui/unreachable/unreachable-code.stderr +++ b/src/test/ui/unreachable/unreachable-code.stderr @@ -9,6 +9,11 @@ note: lint level defined here | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ +note: any code following this expression is unreachable + --> $DIR/unreachable-code.rs:5:3 + | +LL | loop{} + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/unreachable/unreachable-in-call.stderr b/src/test/ui/unreachable/unreachable-in-call.stderr index c740011c4a1..928f5634a12 100644 --- a/src/test/ui/unreachable/unreachable-in-call.stderr +++ b/src/test/ui/unreachable/unreachable-in-call.stderr @@ -9,12 +9,23 @@ note: lint level defined here | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ +note: any code following this expression is unreachable + --> $DIR/unreachable-in-call.rs:13:10 + | +LL | call(diverge(), + | ^^^^^^^^^ error: unreachable call --> $DIR/unreachable-in-call.rs:17:5 | LL | call( | ^^^^ + | +note: any code following this expression is unreachable + --> $DIR/unreachable-in-call.rs:19:9 + | +LL | diverge()); + | ^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/unreachable/unreachable-try-pattern.stderr b/src/test/ui/unreachable/unreachable-try-pattern.stderr index 758aa5a45bc..889df790124 100644 --- a/src/test/ui/unreachable/unreachable-try-pattern.stderr +++ b/src/test/ui/unreachable/unreachable-try-pattern.stderr @@ -9,6 +9,11 @@ note: lint level defined here | LL | #![warn(unreachable_code)] | ^^^^^^^^^^^^^^^^ +note: any code following this expression is unreachable + --> $DIR/unreachable-try-pattern.rs:19:36 + | +LL | let y = (match x { Ok(n) => Ok(n as u32), Err(e) => Err(e) })?; + | ^ warning: unreachable pattern --> $DIR/unreachable-try-pattern.rs:19:24 diff --git a/src/test/ui/unreachable/unwarned-match-on-never.stderr b/src/test/ui/unreachable/unwarned-match-on-never.stderr index ccb70d74311..9ce6e3df804 100644 --- a/src/test/ui/unreachable/unwarned-match-on-never.stderr +++ b/src/test/ui/unreachable/unwarned-match-on-never.stderr @@ -9,12 +9,23 @@ note: lint level defined here | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ +note: any code following this expression is unreachable + --> $DIR/unwarned-match-on-never.rs:8:11 + | +LL | match x {} + | ^ error: unreachable arm --> $DIR/unwarned-match-on-never.rs:15:15 | LL | () => () | ^^ + | +note: any code following this expression is unreachable + --> $DIR/unwarned-match-on-never.rs:14:11 + | +LL | match (return) { + | ^^^^^^^^ error: unreachable expression --> $DIR/unwarned-match-on-never.rs:21:5 @@ -23,6 +34,12 @@ LL | / match () { LL | | () => (), LL | | } | |_____^ + | +note: any code following this expression is unreachable + --> $DIR/unwarned-match-on-never.rs:20:5 + | +LL | return; + | ^^^^^^ error: aborting due to 3 previous errors From cd4b468e07ab27eef87aa8757220d6439defc699 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 18 Sep 2019 19:07:39 -0400 Subject: [PATCH 2/8] Make note better when all arms in a `match` diverge --- src/librustc_typeck/check/_match.rs | 26 +++++++++++++++++-- src/librustc_typeck/check/expr.rs | 5 +++- src/librustc_typeck/check/mod.rs | 33 +++++++++++++++++++------ src/test/ui/reachable/expr_match.stderr | 12 ++++----- 4 files changed, 60 insertions(+), 16 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index a1c937b95ba..86774466ba5 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -43,7 +43,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If there are no arms, that is a diverging match; a special case. if arms.is_empty() { - self.diverges.set(self.diverges.get() | Diverges::Always(expr.span)); + self.diverges.set(self.diverges.get() | Diverges::Always { + span: expr.span, + custom_note: None + }); return tcx.types.never; } @@ -69,7 +72,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // warnings). match all_pats_diverge { Diverges::Maybe => Diverges::Maybe, - Diverges::Always(..) | Diverges::WarnedAlways => Diverges::WarnedAlways, + Diverges::Always { .. } | Diverges::WarnedAlways => Diverges::WarnedAlways, } }).collect(); @@ -167,6 +170,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { prior_arm_ty = Some(arm_ty); } + // If all of the arms in the 'match' diverge, + // and we're dealing with an actual 'match' block + // (as opposed to a 'match' desugared from something else'), + // we can emit a better note. Rather than pointing + // at a diverging expression in an arbitrary arm, + // we can point at the entire 'match' expression + match (all_arms_diverge, match_src) { + (Diverges::Always { .. }, hir::MatchSource::Normal) => { + all_arms_diverge = Diverges::Always { + span: expr.span, + custom_note: Some( + "any code following this `match` expression is unreachable, \ + as all arms diverge" + ) + }; + }, + _ => {} + } + // We won't diverge unless the discriminant or all arms diverge. self.diverges.set(discrim_diverges | all_arms_diverge); diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 3ba453748ff..5733b8d1db1 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -170,7 +170,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Any expression that produces a value of type `!` must have diverged if ty.is_never() { - self.diverges.set(self.diverges.get() | Diverges::Always(expr.span)); + self.diverges.set(self.diverges.get() | Diverges::Always { + span: expr.span, + custom_note: None + }); } // Record the type, which applies it effects. diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 0fced373946..c44648bb9df 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -450,10 +450,20 @@ pub enum Diverges { /// Definitely known to diverge and therefore /// not reach the next sibling or its parent. - /// The `Span` points to the expression - /// that caused us to diverge - /// (e.g. `return`, `break`, etc) - Always(Span), + Always { + /// The `Span` points to the expression + /// that caused us to diverge + /// (e.g. `return`, `break`, etc) + span: Span, + /// In some cases (e.g. a 'match' expression + /// where all arms diverge), we may be + /// able to provide a more informative + /// message to the user. + /// If this is None, a default messsage + /// will be generated, which is suitable + /// for most cases + custom_note: Option<&'static str> + }, /// Same as `Always` but with a reachability /// warning already emitted. @@ -490,7 +500,13 @@ impl ops::BitOrAssign for Diverges { impl Diverges { fn always(self) -> bool { - self >= Diverges::Always(DUMMY_SP) + // Enum comparison ignores the + // contents of fields, so we just + // fill them in with garbage here + self >= Diverges::Always { + span: DUMMY_SP, + custom_note: None + } } } @@ -2312,7 +2328,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn warn_if_unreachable(&self, id: hir::HirId, span: Span, kind: &str) { // FIXME: Combine these two 'if' expressions into one once // let chains are implemented - if let Diverges::Always(orig_span) = self.diverges.get() { + if let Diverges::Always { span: orig_span, custom_note } = self.diverges.get() { // If span arose from a desugaring of `if` or `while`, then it is the condition itself, // which diverges, that we are about to lint on. This gives suboptimal diagnostics. // Instead, stop here so that the `if`- or `while`-expression's block is linted instead. @@ -2324,7 +2340,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let msg = format!("unreachable {}", kind); let mut err = self.tcx().struct_span_lint_hir(lint::builtin::UNREACHABLE_CODE, id, span, &msg); - err.span_note(orig_span, "any code following this expression is unreachable"); + err.span_note( + orig_span, + custom_note.unwrap_or("any code following this expression is unreachable") + ); err.emit(); } } diff --git a/src/test/ui/reachable/expr_match.stderr b/src/test/ui/reachable/expr_match.stderr index b846b92dcec..f587e524d35 100644 --- a/src/test/ui/reachable/expr_match.stderr +++ b/src/test/ui/reachable/expr_match.stderr @@ -9,11 +9,11 @@ note: lint level defined here | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ -note: any code following this expression is unreachable - --> $DIR/expr_match.rs:7:22 +note: any code following this `match` expression is unreachable, as all arms diverge + --> $DIR/expr_match.rs:7:5 | LL | match () { () => return } - | ^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: unreachable statement @@ -22,11 +22,11 @@ error: unreachable statement LL | println!("I am dead"); | ^^^^^^^^^^^^^^^^^^^^^^ | -note: any code following this expression is unreachable - --> $DIR/expr_match.rs:18:31 +note: any code following this `match` expression is unreachable, as all arms diverge + --> $DIR/expr_match.rs:18:5 | LL | match () { () if false => return, () => return } - | ^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: aborting due to 2 previous errors From 9e777eb45de2bf972bbf7f2075fa491e22d2d071 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 18 Sep 2019 19:31:38 -0400 Subject: [PATCH 3/8] Some formatting cleanup --- src/librustc_typeck/check/mod.rs | 13 ++++++------- src/test/ui/reachable/expr_return_in_macro.rs | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c44648bb9df..f6f3173e81c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2338,13 +2338,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind); let msg = format!("unreachable {}", kind); - let mut err = self.tcx().struct_span_lint_hir(lint::builtin::UNREACHABLE_CODE, - id, span, &msg); - err.span_note( - orig_span, - custom_note.unwrap_or("any code following this expression is unreachable") - ); - err.emit(); + self.tcx().struct_span_lint_hir(lint::builtin::UNREACHABLE_CODE, id, span, &msg) + .span_note( + orig_span, + custom_note.unwrap_or("any code following this expression is unreachable") + ) + .emit(); } } } diff --git a/src/test/ui/reachable/expr_return_in_macro.rs b/src/test/ui/reachable/expr_return_in_macro.rs index 198ede6b141..4e57618bf5e 100644 --- a/src/test/ui/reachable/expr_return_in_macro.rs +++ b/src/test/ui/reachable/expr_return_in_macro.rs @@ -1,6 +1,6 @@ // Tests that we generate nice error messages // when an expression is unreachble due to control -// flow inside of a macro expansion +// flow inside of a macro expansion. #![deny(unreachable_code)] macro_rules! early_return { From 6edcfbe59a2067df7aadc18de990b9a86216099e Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 18 Sep 2019 19:48:37 -0400 Subject: [PATCH 4/8] Apply formatting fixes Co-Authored-By: Mazdak Farrokhzad --- src/librustc_typeck/check/_match.rs | 8 ++++---- src/librustc_typeck/check/mod.rs | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 86774466ba5..034cba0f12a 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -170,12 +170,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { prior_arm_ty = Some(arm_ty); } - // If all of the arms in the 'match' diverge, - // and we're dealing with an actual 'match' block - // (as opposed to a 'match' desugared from something else'), + // If all of the arms in the `match` diverge, + // and we're dealing with an actual `match` block + // (as opposed to a `match` desugared from something else'), // we can emit a better note. Rather than pointing // at a diverging expression in an arbitrary arm, - // we can point at the entire 'match' expression + // we can point at the entire `match` expression match (all_arms_diverge, match_src) { (Diverges::Always { .. }, hir::MatchSource::Normal) => { all_arms_diverge = Diverges::Always { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index f6f3173e81c..e424aa67908 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -453,15 +453,15 @@ pub enum Diverges { Always { /// The `Span` points to the expression /// that caused us to diverge - /// (e.g. `return`, `break`, etc) + /// (e.g. `return`, `break`, etc). span: Span, - /// In some cases (e.g. a 'match' expression + /// In some cases (e.g. a `match` expression /// where all arms diverge), we may be /// able to provide a more informative /// message to the user. - /// If this is None, a default messsage + /// If this is `None`, a default messsage /// will be generated, which is suitable - /// for most cases + /// for most cases. custom_note: Option<&'static str> }, @@ -502,7 +502,7 @@ impl Diverges { fn always(self) -> bool { // Enum comparison ignores the // contents of fields, so we just - // fill them in with garbage here + // fill them in with garbage here. self >= Diverges::Always { span: DUMMY_SP, custom_note: None From a8ce93e13a9f1e7d7933ca76f6cae9c8f6127c34 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 18 Sep 2019 20:04:01 -0400 Subject: [PATCH 5/8] Introduce Diverges::always constructor Rename the existing Diverges.always method to Diverges.is_always --- src/librustc_typeck/check/_match.rs | 7 ++----- src/librustc_typeck/check/expr.rs | 5 +---- src/librustc_typeck/check/mod.rs | 14 ++++++++++++-- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 034cba0f12a..9481638fc14 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -43,10 +43,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If there are no arms, that is a diverging match; a special case. if arms.is_empty() { - self.diverges.set(self.diverges.get() | Diverges::Always { - span: expr.span, - custom_note: None - }); + self.diverges.set(self.diverges.get() | Diverges::always(expr.span)); return tcx.types.never; } @@ -198,7 +195,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// When the previously checked expression (the scrutinee) diverges, /// warn the user about the match arms being unreachable. fn warn_arms_when_scrutinee_diverges(&self, arms: &'tcx [hir::Arm], source: hir::MatchSource) { - if self.diverges.get().always() { + if self.diverges.get().is_always() { use hir::MatchSource::*; let msg = match source { IfDesugar { .. } | IfLetDesugar { .. } => "block in `if` expression", diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 5733b8d1db1..049f2eb16bb 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -170,10 +170,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Any expression that produces a value of type `!` must have diverged if ty.is_never() { - self.diverges.set(self.diverges.get() | Diverges::Always { - span: expr.span, - custom_note: None - }); + self.diverges.set(self.diverges.get() | Diverges::always(expr.span)); } // Record the type, which applies it effects. diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index e424aa67908..410eef5e092 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -470,6 +470,16 @@ pub enum Diverges { WarnedAlways } +impl Diverges { + /// Creates a `Diverges::Always` with the provided span and the default note message + fn always(span: Span) -> Diverges { + Diverges::Always { + span, + custom_note: None + } + } +} + // Convenience impls for combinig `Diverges`. impl ops::BitAnd for Diverges { @@ -499,7 +509,7 @@ impl ops::BitOrAssign for Diverges { } impl Diverges { - fn always(self) -> bool { + fn is_always(self) -> bool { // Enum comparison ignores the // contents of fields, so we just // fill them in with garbage here. @@ -3852,7 +3862,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // // #41425 -- label the implicit `()` as being the // "found type" here, rather than the "expected type". - if !self.diverges.get().always() { + if !self.diverges.get().is_always() { // #50009 -- Do not point at the entire fn block span, point at the return type // span, as it is the cause of the requirement, and // `consider_hint_about_removing_semicolon` will point at the last expression From 41e1128969adc0190c946ccbd8b6b89ad197bc34 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 18 Sep 2019 20:07:33 -0400 Subject: [PATCH 6/8] Use 'if let' instead of 'match' --- src/librustc_typeck/check/_match.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 9481638fc14..50fd72f0613 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -173,17 +173,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // we can emit a better note. Rather than pointing // at a diverging expression in an arbitrary arm, // we can point at the entire `match` expression - match (all_arms_diverge, match_src) { - (Diverges::Always { .. }, hir::MatchSource::Normal) => { - all_arms_diverge = Diverges::Always { - span: expr.span, - custom_note: Some( - "any code following this `match` expression is unreachable, \ - as all arms diverge" - ) - }; - }, - _ => {} + if let (Diverges::Always { .. }, hir::MatchSource::Normal) = (all_arms_diverge, match_src) { + all_arms_diverge = Diverges::Always { + span: expr.span, + custom_note: Some( + "any code following this `match` expression is unreachable, as all arms diverge" + ) + }; } // We won't diverge unless the discriminant or all arms diverge. From 034a8fd1dff9bff585a6152bf5c52e882a2bb28b Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 18 Sep 2019 20:14:56 -0400 Subject: [PATCH 7/8] Another formatting fix Co-Authored-By: Mazdak Farrokhzad --- src/librustc_typeck/check/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 410eef5e092..51381447fed 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -471,7 +471,7 @@ pub enum Diverges { } impl Diverges { - /// Creates a `Diverges::Always` with the provided span and the default note message + /// Creates a `Diverges::Always` with the provided `span` and the default note message. fn always(span: Span) -> Diverges { Diverges::Always { span, From d67528ff7dbbe226fa583b9585cee2138533770e Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 18 Sep 2019 21:57:50 -0400 Subject: [PATCH 8/8] Merge inherent impl blocks for `Diverges --- src/librustc_typeck/check/mod.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 51381447fed..1d68d79db88 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -470,16 +470,6 @@ pub enum Diverges { WarnedAlways } -impl Diverges { - /// Creates a `Diverges::Always` with the provided `span` and the default note message. - fn always(span: Span) -> Diverges { - Diverges::Always { - span, - custom_note: None - } - } -} - // Convenience impls for combinig `Diverges`. impl ops::BitAnd for Diverges { @@ -509,6 +499,14 @@ impl ops::BitOrAssign for Diverges { } impl Diverges { + /// Creates a `Diverges::Always` with the provided `span` and the default note message. + fn always(span: Span) -> Diverges { + Diverges::Always { + span, + custom_note: None + } + } + fn is_always(self) -> bool { // Enum comparison ignores the // contents of fields, so we just