---
title: "Why even unused data needs to be valid"
categories: rust
+forum: https://internals.rust-lang.org/t/why-even-unused-data-needs-to-be-valid/12734
---
The Rust compiler has a few assumptions that it makes about the behavior of all code.
but authors of `unsafe` code are themselves responsible for upholding these requirements.
Those assumptions are [listed in the Rust reference](https://doc.rust-lang.org/reference/behavior-considered-undefined.html).
-The one that seems to be most surprising to many people is the clause which says that unsafe code may not *produce* "[...] an invalid value, even in private fields and locals".
+The one that seems to be most surprising to many people is the clause which says that Rust code may not *produce* "[...] an invalid value, even in private fields and locals".
The reference goes on to explain that "*producing* a value happens any time a value is assigned to or read from a place, passed to a function/primitive operation or returned from a function/primitive operation".
In other words, even just *constructing*, for example, an invalid `bool`, is Undefined Behavior---no matter whether that `bool` is ever actually "used" by the program.
The purpose of this post is to explain why that rule is so strict.
I hope it is not very surprising that calling `example` on, e.g., `3` transmuted to `bool` is Undefined Behavior (UB).
When compiling `if`, the compiler assumes that `0` and `1` are the only possible values; there is no saying what could go wrong when that assumption is violated.
+(This is a compiler-understood *validity invariant* that is fixed in the language specification, which is very different from a user-defined *safety invariant*.
+See [this earlier post]({% post_url 2018-08-22-two-kinds-of-invariants %}) for more details on that distinction.)
What is less obvious is why calling `example` on `3` is UB even when there is no such `if` being executed.
To understand why that is important, let us consider the following example:
{% highlight rust %}
fn example(b: bool, num: u32) -> i32 {
let mut acc = 0;
- let incr = if b { 42 } else { 23 }
+ let incr = if b { 42 } else { 23 };
for _i in 0..num {
acc += incr;
}
To support inlining and outlining, we also do not want the function boundary to be relevant, which ultimately leads us to the rule that Rust requires today: whenever data of a given type is *produced* anywhere, the data needs to be valid for that type.
I hope this post was helpful in explaining why Undefined Behavior in Rust is defined the way it is.
-As usual, if you have any comments or questions, let me know in the forums.
+As usual, if you have any comments or questions, let me know in the [forums](https://internals.rust-lang.org/t/why-even-unused-data-needs-to-be-valid/12734).