//@no-rustfix //@aux-build:proc_macros.rs #![allow(clippy::never_loop)] #![warn(clippy::infinite_loop)] extern crate proc_macros; use proc_macros::{external, with_span}; fn do_something() {} fn no_break() { loop { //~^ ERROR: infinite loop detected do_something(); } } fn all_inf() { loop { //~^ ERROR: infinite loop detected loop { //~^ ERROR: infinite loop detected loop { //~^ ERROR: infinite loop detected do_something(); } } do_something(); } } fn no_break_return_some_ty() -> Option { loop { do_something(); return None; } 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 broken out of 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 = 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 = 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) { let opt: Option = Some(1); let mut a: u8 = 0; loop { set_or_ret!(opt, a); } let res: Result = Ok(true); loop { match res { Ok(true) => set_or_ret!(opt, a), _ => do_something(), } } } fn panic_like_macros_1() { loop { do_something(); panic!(); } } fn panic_like_macros_2() { let mut x = 0; loop { do_something(); if true { todo!(); } } loop { do_something(); x += 1; assert_eq!(x, 0); } loop { do_something(); assert!(x % 2 == 0); } loop { do_something(); match Some(1) { Some(n) => println!("{n}"), None => unreachable!("It won't happen"), } } } fn exit_directly(cond: bool) { loop { if cond { std::process::exit(0); } } } trait MyTrait { fn problematic_trait_method() { loop { //~^ ERROR: infinite loop detected do_something(); } } fn could_be_problematic(); } impl MyTrait for String { fn could_be_problematic() { loop { //~^ ERROR: infinite loop detected do_something(); } } } fn inf_loop_in_closure() { let _loop_forever = || { loop { //~^ ERROR: infinite loop detected do_something(); } }; let _somehow_ok = || -> ! { loop { do_something(); } }; } fn inf_loop_in_res() -> Result<(), i32> { Ok(loop { do_something() }) } with_span! { span fn no_loop() {} } with_span! { span fn with_loop() { loop { do_nothing(); } } } fn do_nothing() {} fn span_inside_fn() { with_span! { span loop { do_nothing(); } } } fn main() {}