dtolnay / no-panic

Attribute macro to require that the compiler prove a function can't ever panic
Apache License 2.0
1k stars 13 forks source link

False positive when annotating (non-tail?)-recursive functions #56

Open dflemstr opened 7 months ago

dflemstr commented 7 months ago

When annotating a function that calls itself recursively, a no-panic linker error is reported no matter if the function actually does panic or not.

Steps to reproduce

Consider the following rust program:

#[no_panic::no_panic]
#[inline(never)]
// Attempt to make a nontrivial recursive function; on high opt levels this still gets compiled to
// a tail recursive function in many cases... improvement suggestions welcome!
pub fn collatz(n: usize) -> usize {
    if n == 1 {
        0
    } else if n % 2 == 0 {
        collatz(n/2) + 2
    } else {
        collatz(3*n + 1) + 1
    }
}

pub fn main() {
    let n = std::hint::black_box(collatz(std::hint::black_box(42)));
    println!("{}", n);
}

This produces a linker error:

ERROR[no-panic]: detected panic in function `collatz`

The behavior doesn't change for higher optimization levels, LTO, etc.

This might only happen for functions that are not tail recursive? Tricky to know for sure if this plays a role or not; I haven't been able to conclusively tell from the codegen behavior.

Maybe the drop guard detection pattern behaves differently for recursive functions?