about summary refs log tree commit diff
path: root/tests
diff options
context:
space:
mode:
authorJ-ZhengLi <lizheng135@huawei.com>2023-11-17 18:10:50 +0800
committerJ-ZhengLi <lizheng135@huawei.com>2023-11-17 18:10:50 +0800
commit2d9fc6dfc8160f47f13da9be3fb5fc48ef62880f (patch)
tree3d57fc75f22459f2afdef2e2f4fc8ff65793ba90 /tests
parent406d953820f48947216d6f3a31bef690d5798dca (diff)
downloadrust-2d9fc6dfc8160f47f13da9be3fb5fc48ef62880f.tar.gz
rust-2d9fc6dfc8160f47f13da9be3fb5fc48ef62880f.zip
implement unoptimized code logic for [`infinite_loops`]
Diffstat (limited to 'tests')
-rw-r--r--tests/ui/infinite_loops.rs259
-rw-r--r--tests/ui/infinite_loops.stderr147
2 files changed, 406 insertions, 0 deletions
diff --git a/tests/ui/infinite_loops.rs b/tests/ui/infinite_loops.rs
new file mode 100644
index 00000000000..54ab63d80dd
--- /dev/null
+++ b/tests/ui/infinite_loops.rs
@@ -0,0 +1,259 @@
+//@no-rustfix
+#![allow(clippy::never_loop)]
+#![warn(clippy::infinite_loops)]
+
+fn do_something() {}
+
+fn no_break() {
+    loop {
+        //~^ ERROR: infinite loop detected
+        do_something();
+    }
+}
+
+fn no_break_never_ret() -> ! {
+    loop {
+        do_something();
+    }
+}
+
+fn no_break_never_ret_noise() {
+    loop {
+        fn inner_fn() -> ! {
+            std::process::exit(0);
+        }
+        do_something();
+    }
+}
+
+fn has_direct_break_1() {
+    loop {
+        do_something();
+        break;
+    }
+}
+
+fn has_direct_break_2() {
+    'outer: loop {
+        do_something();
+        break 'outer;
+    }
+}
+
+fn has_indirect_break_1(cond: bool) {
+    'outer: loop {
+        loop {
+            if cond {
+                break 'outer;
+            }
+        }
+    }
+}
+
+fn has_indirect_break_2(stop_num: i32) {
+    'outer: loop {
+        for x in 0..5 {
+            if x == stop_num {
+                break 'outer;
+            }
+        }
+    }
+}
+
+fn break_inner_but_not_outer_1(cond: bool) {
+    loop {
+        //~^ ERROR: infinite loop detected
+        loop {
+            if cond {
+                break;
+            }
+        }
+    }
+}
+
+fn break_inner_but_not_outer_2(cond: bool) {
+    loop {
+        //~^ ERROR: infinite loop detected
+        'inner: loop {
+            loop {
+                if cond {
+                    break 'inner;
+                }
+            }
+        }
+    }
+}
+
+fn break_outer_but_not_inner() {
+    loop {
+        loop {
+            //~^ ERROR: infinite loop detected
+            do_something();
+        }
+        break;
+    }
+}
+
+fn can_break_both_inner_and_outer(cond: bool) {
+    'outer: loop {
+        loop {
+            if cond {
+                break 'outer;
+            } else {
+                break;
+            }
+        }
+    }
+}
+
+fn break_wrong_loop(cond: bool) {
+    // 'inner has statement to break 'outer loop, but it was breaked early by a labeled child loop
+    'outer: loop {
+        loop {
+            //~^ ERROR: infinite loop detected
+            'inner: loop {
+                loop {
+                    loop {
+                        break 'inner;
+                    }
+                    break 'outer;
+                }
+            }
+        }
+    }
+}
+
+fn has_direct_return(cond: bool) {
+    loop {
+        if cond {
+            return;
+        }
+    }
+}
+
+fn ret_in_inner(cond: bool) {
+    loop {
+        loop {
+            if cond {
+                return;
+            }
+        }
+    }
+}
+
+enum Foo {
+    A,
+    B,
+    C,
+}
+
+fn match_like() {
+    let opt: Option<u8> = Some(1);
+    loop {
+        //~^ ERROR: infinite loop detected
+        match opt {
+            Some(v) => {
+                println!("{v}");
+            },
+            None => {
+                do_something();
+            },
+        }
+    }
+
+    loop {
+        match opt {
+            Some(v) => {
+                println!("{v}");
+            },
+            None => {
+                do_something();
+                break;
+            },
+        }
+    }
+
+    let result: Result<u8, u16> = Ok(1);
+    loop {
+        let _val = match result {
+            Ok(1) => 1 + 1,
+            Ok(v) => v / 2,
+            Err(_) => return,
+        };
+    }
+
+    loop {
+        let Ok(_val) = result else { return };
+    }
+
+    loop {
+        let Ok(_val) = result.map(|v| 10) else { break };
+    }
+
+    loop {
+        //~^ ERROR: infinite loop detected
+        let _x = matches!(result, Ok(v) if v != 0).then_some(0);
+    }
+
+    loop {
+        //~^ ERROR: infinite loop detected
+        // This `return` does not return the function, so it doesn't count
+        let _x = matches!(result, Ok(v) if v != 0).then(|| {
+            if true {
+                return;
+            }
+            do_something();
+        });
+    }
+
+    let mut val = 0;
+    let mut fooc = Foo::C;
+
+    loop {
+        val = match fooc {
+            Foo::A => 0,
+            Foo::B => {
+                fooc = Foo::C;
+                1
+            },
+            Foo::C => break,
+        };
+    }
+
+    loop {
+        val = match fooc {
+            Foo::A => 0,
+            Foo::B => 1,
+            Foo::C => {
+                break;
+            },
+        };
+    }
+}
+
+macro_rules! set_or_ret {
+    ($opt:expr, $a:expr) => {{
+        match $opt {
+            Some(val) => $a = val,
+            None => return,
+        }
+    }};
+}
+
+fn ret_in_macro(opt: Option<u8>) {
+    let opt: Option<u8> = Some(1);
+    let mut a: u8 = 0;
+    loop {
+        set_or_ret!(opt, a);
+    }
+
+    let res: Result<bool, u8> = Ok(true);
+    loop {
+        match res {
+            Ok(true) => set_or_ret!(opt, a),
+            _ => do_something(),
+        }
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/infinite_loops.stderr b/tests/ui/infinite_loops.stderr
new file mode 100644
index 00000000000..f6bca43f1a4
--- /dev/null
+++ b/tests/ui/infinite_loops.stderr
@@ -0,0 +1,147 @@
+error: infinite loop detected
+  --> $DIR/infinite_loops.rs:8:5
+   |
+LL | /     loop {
+LL | |
+LL | |         do_something();
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::infinite-loops` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::infinite_loops)]`
+help: if this is intentional, consider specifing `!` as function return
+   |
+LL | fn no_break() -> ! {
+   |               ++++
+
+error: infinite loop detected
+  --> $DIR/infinite_loops.rs:21:5
+   |
+LL | /     loop {
+LL | |         fn inner_fn() -> ! {
+LL | |             std::process::exit(0);
+LL | |         }
+LL | |         do_something();
+LL | |     }
+   | |_____^
+   |
+help: if this is intentional, consider specifing `!` as function return
+   |
+LL | fn no_break_never_ret_noise() -> ! {
+   |                               ++++
+
+error: infinite loop detected
+  --> $DIR/infinite_loops.rs:64:5
+   |
+LL | /     loop {
+LL | |
+LL | |         loop {
+LL | |             if cond {
+...  |
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+help: if this is intentional, consider specifing `!` as function return
+   |
+LL | fn break_inner_but_not_outer_1(cond: bool) -> ! {
+   |                                            ++++
+
+error: infinite loop detected
+  --> $DIR/infinite_loops.rs:75:5
+   |
+LL | /     loop {
+LL | |
+LL | |         'inner: loop {
+LL | |             loop {
+...  |
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+help: if this is intentional, consider specifing `!` as function return
+   |
+LL | fn break_inner_but_not_outer_2(cond: bool) -> ! {
+   |                                            ++++
+
+error: infinite loop detected
+  --> $DIR/infinite_loops.rs:89:9
+   |
+LL | /         loop {
+LL | |
+LL | |             do_something();
+LL | |         }
+   | |_________^
+   |
+help: if this is intentional, consider specifing `!` as function return
+   |
+LL | fn break_outer_but_not_inner() -> ! {
+   |                                ++++
+
+error: infinite loop detected
+  --> $DIR/infinite_loops.rs:112:9
+   |
+LL | /         loop {
+LL | |
+LL | |             'inner: loop {
+LL | |                 loop {
+...  |
+LL | |             }
+LL | |         }
+   | |_________^
+   |
+help: if this is intentional, consider specifing `!` as function return
+   |
+LL | fn break_wrong_loop(cond: bool) -> ! {
+   |                                 ++++
+
+error: infinite loop detected
+  --> $DIR/infinite_loops.rs:152:5
+   |
+LL | /     loop {
+LL | |
+LL | |         match opt {
+LL | |             Some(v) => {
+...  |
+LL | |         }
+LL | |     }
+   | |_____^
+   |
+help: if this is intentional, consider specifing `!` as function return
+   |
+LL | fn match_like() -> ! {
+   |                 ++++
+
+error: infinite loop detected
+  --> $DIR/infinite_loops.rs:193:5
+   |
+LL | /     loop {
+LL | |
+LL | |         let _x = matches!(result, Ok(v) if v != 0).then_some(0);
+LL | |     }
+   | |_____^
+   |
+help: if this is intentional, consider specifing `!` as function return
+   |
+LL | fn match_like() -> ! {
+   |                 ++++
+
+error: infinite loop detected
+  --> $DIR/infinite_loops.rs:198:5
+   |
+LL | /     loop {
+LL | |
+LL | |         // This `return` does not return the function, so it doesn't count
+LL | |         let _x = matches!(result, Ok(v) if v != 0).then(|| {
+...  |
+LL | |         });
+LL | |     }
+   | |_____^
+   |
+help: if this is intentional, consider specifing `!` as function return
+   |
+LL | fn match_like() -> ! {
+   |                 ++++
+
+error: aborting due to 9 previous errors
+