Series: The Rust Annals
Vol. I Issue 99 nlopes.dev
Announcing Rust 1.98.0
Rust 1.98 adds algebraic floating-point operations that permit otherwise-invalid real-number optimizations, introduces direct integer formatting into a reusable buffer, and guarantees that moving a manually dropped ManuallyDrop<Box<_>> is not undefined behavior. Together, these changes offer explicitly nondeterministic floating-point optimization, lower-overhead decimal formatting, and a firmer unsafe-code contract.
Algebraic floating-point methods permit reordered and vectorized computation
The floating-point types f32 and f64 now have algebraic methods for addition, subtraction, multiplication, division, and remainder. These methods allow optimizations based on the algebraic properties of real numbers even though those properties do not generally hold under the limitations of floating-point representations. The exact set of optimizations is unspecified, but may resemble those enabled by -ffast-math in other languages.
Floating-point addition is not associative, so a + b + c + d must ordinarily be evaluated in its parsed left-associative order, ((a + b) + c) + d. Written as a chain of algebraic_add calls, the compiler may instead reorder it as (a + b) + (c + d), allowing the partial sums to be evaluated simultaneously. Using these methods also often enables broader loop vectorization.
The results are nondeterministic because the compiler may choose different optimizations, but the methods never cause undefined behavior. The library documentation and API change proposal provide further details.
Primitive integers can format directly into a reusable buffer
Every primitive integer type now has a format_into method. It accepts &mut NumBuffer<Self>, an opaque buffer large enough to hold the decimal representation of any value of that integer type, and returns a formatted &str whose lifetime is borrowed from the buffer.
The method bypasses much of the dynamic dispatch involved in buffered write! formatting. The itoa-benchmark repository shows format_into performing similarly to itoa itself, so it could serve as a standard-library replacement for that dependency and others like it.
Moving a manually dropped Box is now guaranteed not to be undefined behavior
Before Rust 1.96.0, a compiler bug made the following code undefined behavior:
let mut x = ManuallyDrop::new(Box::new(1));
unsafe { ManuallyDrop::drop(&mut x) };
let x = x; // UB!
Moving a Box after it has been dropped and deallocated is undefined behavior. ManuallyDrop used to propagate that rule, so moving a ManuallyDrop<Box<_>> after dropping the contained box was also treated as undefined behavior.
Rust 1.96.0 fixed the compiler behavior, making this code no longer undefined behavior. Rust 1.98 updates the documentation to provide a stable guarantee that it will continue not to be undefined behavior. See the ManuallyDrop documentation and RFC 3336 for details.