Therdel
Therdel

Reputation: 33

Is this "possibly-uninitialized" compiler error a false alarm? [rustc 1.51.0]

I was hit with the possibly-uninitialized variable error, although I'm convinced that this should never be the case.
(The rustc --version is rustc 1.51.0 (2fd73fabe 2021-03-23))

fn example(discriminant: bool) {
    let value;
    if discriminant {
        value = 0;
    }

    // more code [...]

    if discriminant {
        println!("{}", value);
    }
}

Here's the error message:

    error[E0381]: borrow of possibly-uninitialized variable: `value`
      --> src/raytracing/intersect.rs:8:24
       |
    10 |         println!("{}", value);
       |                        ^^^^^ use of possibly-uninitialized `value`

Reasoning

I did expect the example to compile (even though seperating the if-blocks as shown isn't "good style" IMHO):

Possible mitigation

The error can be 'silenced' by initializing value with a temporary value.
I strongly disagree with this approach because

Question

Can someone clarify if this case is intended behaviour or maybe a compiler bug?

Upvotes: 3

Views: 603

Answers (1)

bk2204
bk2204

Reputation: 76804

You're not the first person to see this behavior, and generally I would not consider it a bug. In your case, the condition is very simple and obvious, and it's easy for you and me to reason about this condition. However, in general, the condition does not need to be obvious and, for example, the second case could have additional conditions that are hard to reason about, even though the code is correct.

Moreover, the kind of analysis you want the compiler to do (determine which code is reachable based on conditions) is usually only done when the compiler is optimizing. Therefore, even if the compiler had support for this kind of analysis, it probably wouldn't work in debug mode. It also doesn't work in all cases even in the best optimizing compilers and static analysis tools.

If you have a philosophical objection to initializing a dummy value in this case, you can use an Option:

fn example(discriminant: bool) {
    let value = if discriminant {
        Some(0)
    } else {
        None
    };

    // more code [...]

    if discriminant {
        println!("{}", value.unwrap());
    }
}

In this case, your value is always initialized, and in the second portion, you're asserting that it contains a suitable non-None value. If you're in release mode, the compiler may be able to determine that your code is correct and optimize it to omit the Option (or it may not).

Upvotes: 2

Related Questions