about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-11-08 11:41:22 +0000
committerbors <bors@rust-lang.org>2020-11-08 11:41:22 +0000
commitabfa331f266c82fcd62d26ff248f92fe59e09956 (patch)
treec679b1f86c68e0b1eddb249c772bf3bc2fb4d8ab
parent96d5f45adee883c565062fbb44de7ea29918539d (diff)
parent00dee9d9160e9030d387f2cef1ec2b6422478229 (diff)
downloadrust-abfa331f266c82fcd62d26ff248f92fe59e09956.tar.gz
rust-abfa331f266c82fcd62d26ff248f92fe59e09956.zip
Auto merge of #6205 - josephlr:empty-loop2, r=flip1995
Enable empty_loop lint for no_std crates

Depends on #6162. Fixes #6161

We skip the lint if the `loop {}` is in the `#[panic_handler]` as the
main recommendation we give is to panic, which obviously isn't
possible in a panic handler.

changelog: Enable empty_loop lint for no_std crates
-rw-r--r--clippy_lints/src/loops.rs28
-rw-r--r--clippy_lints/src/utils/mod.rs7
-rw-r--r--tests/ui/crashes/ice-360.stderr2
-rw-r--r--tests/ui/empty_loop.stderr6
-rw-r--r--tests/ui/empty_loop_no_std.rs7
-rw-r--r--tests/ui/empty_loop_no_std.stderr19
6 files changed, 49 insertions, 20 deletions
diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs
index 32c2562ee95..b246245af24 100644
--- a/clippy_lints/src/loops.rs
+++ b/clippy_lints/src/loops.rs
@@ -4,10 +4,10 @@ use crate::utils::sugg::Sugg;
 use crate::utils::usage::{is_unused, mutated_variables};
 use crate::utils::{
     contains_name, get_enclosing_block, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait,
-    indent_of, is_integer_const, is_no_std_crate, is_refutable, is_type_diagnostic_item, last_path_segment,
-    match_trait_method, match_type, match_var, multispan_sugg, qpath_res, single_segment_path, snippet,
-    snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg,
-    span_lint_and_then, sugg, SpanlessEq,
+    indent_of, is_in_panic_handler, is_integer_const, is_no_std_crate, is_refutable, is_type_diagnostic_item,
+    last_path_segment, match_trait_method, match_type, match_var, multispan_sugg, qpath_res, single_segment_path,
+    snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_help,
+    span_lint_and_sugg, span_lint_and_then, sugg, SpanlessEq,
 };
 use if_chain::if_chain;
 use rustc_ast::ast;
@@ -543,17 +543,15 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
         // (also matches an explicit "match" instead of "if let")
         // (even if the "match" or "if let" is used for declaration)
         if let ExprKind::Loop(ref block, _, LoopSource::Loop) = expr.kind {
-            // also check for empty `loop {}` statements
-            // TODO(issue #6161): Enable for no_std crates (outside of #[panic_handler])
-            if block.stmts.is_empty() && block.expr.is_none() && !is_no_std_crate(cx.tcx.hir().krate()) {
-                span_lint_and_help(
-                    cx,
-                    EMPTY_LOOP,
-                    expr.span,
-                    "empty `loop {}` wastes CPU cycles",
-                    None,
-                    "You should either use `panic!()` or add `std::thread::sleep(..);` to the loop body.",
-                );
+            // also check for empty `loop {}` statements, skipping those in #[panic_handler]
+            if block.stmts.is_empty() && block.expr.is_none() && !is_in_panic_handler(cx, expr) {
+                let msg = "empty `loop {}` wastes CPU cycles";
+                let help = if is_no_std_crate(cx.tcx.hir().krate()) {
+                    "you should either use `panic!()` or add a call pausing or sleeping the thread to the loop body"
+                } else {
+                    "you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body"
+                };
+                span_lint_and_help(cx, EMPTY_LOOP, expr.span, msg, None, help);
             }
 
             // extract the expression from the first statement (if any) in a block
diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs
index 8e4149df032..cba3a050249 100644
--- a/clippy_lints/src/utils/mod.rs
+++ b/clippy_lints/src/utils/mod.rs
@@ -468,6 +468,13 @@ pub fn is_entrypoint_fn(cx: &LateContext<'_>, def_id: DefId) -> bool {
         .map_or(false, |(entry_fn_def_id, _)| def_id == entry_fn_def_id.to_def_id())
 }
 
+/// Returns `true` if the expression is in the program's `#[panic_handler]`.
+pub fn is_in_panic_handler(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
+    let parent = cx.tcx.hir().get_parent_item(e.hir_id);
+    let def_id = cx.tcx.hir().local_def_id(parent).to_def_id();
+    Some(def_id) == cx.tcx.lang_items().panic_impl()
+}
+
 /// Gets the name of the item the expression is in, if available.
 pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> {
     let parent_id = cx.tcx.hir().get_parent_item(expr.hir_id);
diff --git a/tests/ui/crashes/ice-360.stderr b/tests/ui/crashes/ice-360.stderr
index bb03ce40355..0eb7bb12b35 100644
--- a/tests/ui/crashes/ice-360.stderr
+++ b/tests/ui/crashes/ice-360.stderr
@@ -19,7 +19,7 @@ LL |         loop {}
    |         ^^^^^^^
    |
    = note: `-D clippy::empty-loop` implied by `-D warnings`
-   = help: You should either use `panic!()` or add `std::thread::sleep(..);` to the loop body.
+   = help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/empty_loop.stderr b/tests/ui/empty_loop.stderr
index fd3979f259a..555f3d3d884 100644
--- a/tests/ui/empty_loop.stderr
+++ b/tests/ui/empty_loop.stderr
@@ -5,7 +5,7 @@ LL |     loop {}
    |     ^^^^^^^
    |
    = note: `-D clippy::empty-loop` implied by `-D warnings`
-   = help: You should either use `panic!()` or add `std::thread::sleep(..);` to the loop body.
+   = help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body
 
 error: empty `loop {}` wastes CPU cycles
   --> $DIR/empty_loop.rs:11:9
@@ -13,7 +13,7 @@ error: empty `loop {}` wastes CPU cycles
 LL |         loop {}
    |         ^^^^^^^
    |
-   = help: You should either use `panic!()` or add `std::thread::sleep(..);` to the loop body.
+   = help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body
 
 error: empty `loop {}` wastes CPU cycles
   --> $DIR/empty_loop.rs:15:9
@@ -21,7 +21,7 @@ error: empty `loop {}` wastes CPU cycles
 LL |         'inner: loop {}
    |         ^^^^^^^^^^^^^^^
    |
-   = help: You should either use `panic!()` or add `std::thread::sleep(..);` to the loop body.
+   = help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/empty_loop_no_std.rs b/tests/ui/empty_loop_no_std.rs
index 879d1d5d916..4553d3ec505 100644
--- a/tests/ui/empty_loop_no_std.rs
+++ b/tests/ui/empty_loop_no_std.rs
@@ -10,13 +10,18 @@ use core::panic::PanicInfo;
 
 #[start]
 fn main(argc: isize, argv: *const *const u8) -> isize {
+    // This should trigger the lint
     loop {}
 }
 
 #[panic_handler]
 fn panic(_info: &PanicInfo) -> ! {
+    // This should NOT trigger the lint
     loop {}
 }
 
 #[lang = "eh_personality"]
-extern "C" fn eh_personality() {}
+extern "C" fn eh_personality() {
+    // This should also trigger the lint
+    loop {}
+}
diff --git a/tests/ui/empty_loop_no_std.stderr b/tests/ui/empty_loop_no_std.stderr
new file mode 100644
index 00000000000..520248fcb68
--- /dev/null
+++ b/tests/ui/empty_loop_no_std.stderr
@@ -0,0 +1,19 @@
+error: empty `loop {}` wastes CPU cycles
+  --> $DIR/empty_loop_no_std.rs:14:5
+   |
+LL |     loop {}
+   |     ^^^^^^^
+   |
+   = note: `-D clippy::empty-loop` implied by `-D warnings`
+   = help: you should either use `panic!()` or add a call pausing or sleeping the thread to the loop body
+
+error: empty `loop {}` wastes CPU cycles
+  --> $DIR/empty_loop_no_std.rs:26:5
+   |
+LL |     loop {}
+   |     ^^^^^^^
+   |
+   = help: you should either use `panic!()` or add a call pausing or sleeping the thread to the loop body
+
+error: aborting due to 2 previous errors
+