What Is New in Rust 1.86
| Category | Highlights |
|---|---|
| New Features | Trait upcasting, safe #[target_feature] functions, get_disjoint_mut for slices and HashMap |
| Improvements | Debug assertions for non-null pointers, missing_abi lint now warns by default |
| Deprecations | Tier-2 target i586-pc-windows-msvc will be removed in 1.87 |
How does trait upcasting work in Rust 1.86?
Trait upcasting lets you coerce a dyn Trait reference directly into a dyn Supertrait reference without any boilerplate.
- Works for any pointer type:
&dyn Trait,Arc<dyn Trait>,*const dyn Trait, etc. - Eliminates the need for custom
as_supertraitmethods. - Useful with
Anyto downcast without extra trait methods.
trait Trait: Supertrait {}
trait Supertrait {}
fn upcast(x: &dyn Trait) -> &dyn Supertrait {
x
}
What new APIs enable mutable access to multiple collection elements?
The standard library now provides get_disjoint_mut on slices and HashMap to safely obtain several mutable references at once.
- Returns
Result<[&mut T; N], _>where each element is guaranteed to be disjoint. - Works with index arrays, ranges, and inclusive ranges.
- Prevents the classic "two mutable borrows" compile-time error.
let v = &mut [1, 2, 3];
if let Ok([a, b]) = v.get_disjoint_mut([0, 2]) {
*a = 413;
*b = 612;
}
Can safe functions now be annotated with #[target_feature]?
Yes, the target_feature_11 feature stabilizes the ability to mark safe functions with #[target_feature].
- Safe functions can only be called from other functions that have the same target feature.
- They can be called inside an
unsafeblock when the caller guarantees the feature is present. - They cannot be passed to generic
Fn*bounds or coerced to function pointers outside a matching feature context.
#[target_feature(enable = "avx2")]
fn requires_avx2() {
// ...
}
#[target_feature(enable = "avx2")]
fn safe_callsite() {
requires_avx2();
}
What runtime safety checks have been added for debug builds?
Debug builds now assert that pointers used for non-zero-sized reads, writes, or reborrows are non-null.
- The check triggers a panic when a null pointer is dereferenced.
- Only active when
debug_assertionsare enabled; release builds are unaffected. - Helps catch accidental null derefs that previously only produced warnings.
let _x = *std::ptr::null::<u8>();
let _x = &*std::ptr::null::<u8>();
Which ABI-related lint has changed and what does it mean for extern blocks?
The new missing_abi lint warns when the ABI is omitted from extern declarations.
- Previously, omitting the ABI defaulted to the C ABI silently.
- Now the compiler encourages explicit
extern "C"(or other ABI) to improve readability. - Helps avoid accidental mismatches when targeting non-C ABIs.
Frequently Asked Questions
Does trait upcasting require any unsafe code?
No, the coercion is performed entirely in safe Rust.
How can I obtain two mutable references from a slice without violating the borrow checker?
Use slice::get_disjoint_mut and handle the Result it returns.
What is the correct way to declare an extern function after the missing_abi lint change?
Write extern "C" fn foo() instead of just extern fn foo().
Can I call a #[target_feature] safe function from regular code?
Yes, but you must wrap the call in an unsafe block and ensure the CPU feature is present.
Will the new null-pointer debug assertions affect release builds?
No, they are only active when debug assertions are enabled.
Which Windows target is being deprecated in the next release?
The i586-pc-windows-msvc target will be removed in Rust 1.87.