What Is New in Rust 1.45
| Category | Highlights |
|---|---|
| New Features | Saturating float-to-int casts, unsafe to_int_unchecked, function-like procedural macros in expression/pattern/statement positions, inclusive char range iteration. |
| Improvements | Library APIs stabilized for char ranges, better ergonomics for web frameworks like Rocket. |
| Bug Fixes | Fixed long-standing unsoundness in casts that could produce undefined behavior. |
How does Rust 1.45 prevent undefined behavior when casting floats to integers?
Rust 1.45 changes the built-in as cast to perform a saturating conversion instead of producing a poison value.
- Values larger than the target type clamp to the maximum (e.g.,
300.0_f32 as u8yields255). - Negative values and
NaNclamp to zero. - If you really need the old unchecked behavior, use the new unsafe method
to_int_unchecked.
let big = 300.0_f32;
let small = -10.0_f32;
let nan = f32::NAN;
println!("big → {}", big as u8); // 255
println!("small → {}", small as u8); // 0
println!("nan → {}", nan as u8); // 0
// Unsafe unchecked cast (use with extreme caution)
let raw: u8 = unsafe { big.to_int_unchecked() };
This matters if you relied on wrap-around semantics; you'll now see clamped results.
Can I use function-like procedural macros in more places after Rust 1.45?
Yes, Rust 1.45 expands function-like procedural macros to expression, pattern, and statement positions.
- Item position (stable since 1.30) remains unchanged.
- Expression position lets you write
let x = mac!();. - Pattern position enables matching like
match v { mac!() => ... }. - Statement position allows a macro call as a standalone statement.
mac!(); // item position (old)
fn main() {
let value = mac!(); // expression
match value {
mac!() => println!("matched"), // pattern
}
mac!(); // statement
}
This unlocks frameworks such as Rocket to run on stable Rust without nightly-only features.
What new iteration capabilities does Rust 1.45 add for characters?
Rust 1.45 lets you iterate over inclusive character ranges using the ..= syntax.
for ch in 'a'..='z' {
print!("{}", ch);
}
println!(); // prints abcdefghijklmnopqrstuvwxyz
In practice this simplifies Unicode-aware loops and removes the need for external crates for simple ASCII ranges.
Do existing as casts need to be audited after upgrading to Rust 1.45?
Most teams will need to review code that casts large floats to small integers because the semantics have changed from wrap-around to saturation.
- If the original intent was to clamp, the code now behaves correctly without changes.
- If the original intent relied on overflow wrapping, you must either adjust the logic or switch to the unsafe
to_int_uncheckedmethod.
Running the test suite with edge-case values (e.g., >255.0 for u8) will quickly reveal any regressions.
Frequently Asked Questions
Does the new saturating cast affect existing as conversions?
Yes, as now clamps out-of-range values instead of producing undefined behavior.
How do I perform an unchecked float-to-int cast in Rust 1.45?
You can use unsafe { value.to_int_unchecked() } to bypass the saturation checks.
Which web frameworks benefit from the procedural macro stabilization?
Rocket can now compile on stable Rust without nightly features, thanks to the new macro positions.
Can I now write for ch in 'a'..='z' in stable Rust?
Yes, inclusive char ranges are supported directly in stable Rust 1.45.
Are there any breaking changes introduced in Rust 1.45?
No breaking changes were introduced; only behavior of as casts was tightened.
Do I need to update Cargo or Clippy separately after upgrading the compiler?
Updating the toolchain with rustup update stable also brings the matching Cargo and Clippy versions.