Other commenters have mentioned the use case for FFI, and there's a very small niche use case for type punning, but there's one thing that this enables you to do that was absolutely not possible with the language previously.

This is zero cost stack allocation of data in a way which avoids destructors.

Basically, currently, in Rust, if you want to allocate a type and avoid destructors being run, you have to write a wrapper around `Option<YourType>` that nulls the option in its destructors. Or you heap allocate it and turn the box into a raw pointer after allocation. Both have overhead. The zero-overhead way of doing it is to stack allocate an array and cast pointers, but then you need to know the size beforehand.

With unions, you can stack allocate a `union Foo {x: YourType}` and just use that. Unions don't have destructors, so this stack allocates enough space for your type, and lets you unsafely but conveniently access it as your type (no ugly pointer casting hacks), but you can guarantee that destructors won't be run.

The obvious question here is -- why is this even necessary? Surely you can just call mem::forget to avoid destructors right before the function returns.

However, destructors also get run whilst panicking, so if your function accepts a callback, and that callback panics, you can't avoid destructors without the overhead mentioned before.

For a concrete example of this use case, check out ArcBorrow::with_arc() (https://doc.servo.org/servo_arc/struct.ArcBorrow.html). ArcBorrow<'a, T> is basically a borrowed reference to a T that is known to be backed by an Arc (atomic reference counted type). You can obtain borrowed references to an Arc normally, which is great -- lets you share the data without bumping atomic reference counts all the time and paying the atomic overhead. But if you have an &T -- a borrowed reference to a T -- there's no way to bump the reference count on that if you need to escape the borrow; since there's no guarantee that the &T borrows from an Arc allocation and not something else. So you must pass down an &Arc<T>, and that has double indirection. There are other reasons (pertaining to the existence of RawOffsetArc, which has to do with FFI constraints) as to why &Arc<T> won't work for us there, but I won't get into those. ArcBorrow<'a, T> lets us freely pass around borrows of &T which can be cloned as an Arc if necessary.

Anyway, ArcBorrow has a with_arc method (https://doc.servo.org/servo_arc/struct.ArcBorrow.html#method...). This takes a closure and passes an &Arc<T> to it.

But we don't have an Arc<T>, we have an ArcBorrow<T>, which has a different representation (in particular, ArcBorrow contains a pointer to the data, whereas Arc contains a pointer to the allocation, which starts earlier because of the refcount).

So we construct a fake Arc<T> on the stack (https://doc.servo.org/src/servo_arc/lib.rs.html#884-907), and share it with the closure. Because it's a fake Arc<T> we can't actually let its destructors be run, so we put it inside NoDrop, which on nightly uses unions (but on stable uses the non-zero-cost methods I mentioned above).

I use this same trick in array-init (https://github.com/Manishearth/array-init/blob/a0cb08928b42d...), where I stack allocate an uninitialized array and let you fill in the elements with a closure. If the closure panics the destructor of the _partially_ initialized array should not run, so again, it's in a NoDrop.

In general when writing unsafe abstractions you often need escape hatches like these.