"this expression will panic at run-time" warnings can't be suppressed

87ca576
Opened by Emilio Cobos Álvarez at 2024-12-21 04:50:13

Here's a reduced test-case:

let a = [0u8; 2usize];
println!("{}", a[0]);
println!("{}", a[1]);

if a.len() == 3 {
    println!("{}", a[2]);
}

Now some background.

In Servo we generate large amounts of rust code using different systems. Today @upsuper was trying to generate shared code for two different structs that have different fields, let's simplify it as:

struct Foo {
    bar: [u8; 2],
}

struct Bar {
    bar: [u8; 3],
}

To generate shared code for both, he wanted to do something like:

let instance = ${var}; // Instance is either `Foo` or `Bar`, we'll expand this twice.
do_something_with(instance.bar[0]);
do_something_with(instance.bar[1]);
if instance.bar.len() == 3 {
    do_something_with(instance.bar[2]);
}

However, that generates an unsuppresable warning like:

^^^^ index out of bounds: the len is 2 but the index is 2

So it seems that Rust doesn't account for that code being unreachable in the Foo case.

In any case, being able to suppress that warning would've made this code straight-forward. Instead of that we probably need to work around it with something like:

#[inline(always)]
fn doit(a: &[u8]) {
    do_something_with(a[0]);
    do_something_with(a[1]);
    if a.len() == 3 {
        do_something_with(a[2]);
    }
}

doit(&instance.bar)

Which is not great.

  1. Another way to workaround it is probably something like

    let len = a.len();
    if len == 3 {
      do_something(&a[len - 1]);
    }
    

    It has fewer boilerplate than the approach mentioned above, but could still be annoying...

    Xidorn Quan at 2017-11-15 00:11:43

  2. In https://github.com/servo/servo/pull/19227 I’ve replaced this:

    if a.len() == 3 {
        println!("{}", a[2]);
    }
    

    With this:

    if let Some(third) = a.get(2) {
        println!("{}", third);
    }
    

    Simon Sapin at 2017-11-15 13:50:48

  3. Run into this with associated constants and division by zero, mildly annoying but I found a workarround (a.wrapping_div(b) instead of a/b): Playground

    Badel2 at 2018-03-28 00:25:08

  4. I think this issue can be closed, now these warnings can be suppressed using #[allow(unconditional_panic)] which can be found in the error message:

       Compiling playground v0.0.1 (/playground)
    error: this operation will panic at runtime
     --> src/main.rs:8:20
      |
    8 |     println!("{}", a[2]);
      |                    ^^^^ index out of bounds: the length is 2 but the index is 2
      |
      = note: `#[deny(unconditional_panic)]` on by default
    
    error: could not compile `playground` due to previous error
    

    Badel2 at 2021-11-10 01:06:58