nixcfg/config/agents/skills/rust-recent-features/SKILL.md
Harald Hoyer a935e77f83 feat(skills): add rust-recent-features reference skill
Documents Rust language, stdlib, and Cargo features stabilized after the
~2025 training cutoff (1.85–1.95, 2024 edition) so agents generate
current syntax instead of relying on a stale mental model.
2026-05-21 23:34:28 +02:00

207 lines
9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
name: rust-recent-features
description: Reference for Rust language, stdlib, and Cargo features stabilized AFTER a ~2025 training cutoff (Rust 1.85 through 1.95, Feb 2025 Apr 2026), including the 2024 edition. Load this on ANY Rust task — writing, reviewing, or fixing Rust code — so syntax and APIs reflect current stable Rust instead of a stale mental model. Especially relevant when targeting edition 2024.
---
# Recent Rust features (1.85 → 1.95)
You may have been trained before these were stable. Treat this file as ground
truth over your prior beliefs. When unsure whether something compiles, prefer
checking with `cargo check` over guessing — the toolchain is authoritative.
Versions and dates: 1.85 (2025-02-20, **2024 edition**), 1.86 (2025-04-03),
1.87 (2025-05-15), 1.88 (2025-06-26), 1.89 (2025-08-07), 1.90 (2025-09-18),
1.91 (2025-10-30), 1.92 (2025-12-11), 1.93 (2026-01-22), 1.94 (2026-03-05),
1.95 (2026-04-16).
---
## 1. The 2024 edition (stable since 1.85) — read this first
If `Cargo.toml` has `edition = "2024"`, these are the changes most likely to
trip up a pre-2025 model. Migrate an existing crate with
`cargo fix --edition` after bumping the edition key.
- **Unsafe attributes.** `#[no_mangle]`, `#[export_name]`, and `#[link_section]`
must now be wrapped in `unsafe(...)`:
```rust
#[unsafe(no_mangle)]
pub extern "C" fn foo() {}
#[unsafe(export_name = "bar")]
fn b() {}
```
Writing a bare `#[no_mangle]` is an error in edition 2024.
- **`unsafe extern` blocks.** `extern` blocks declaring foreign items must be
`unsafe extern`. Individual items may be marked `safe` or `unsafe`:
```rust
unsafe extern "C" {
safe fn always_safe(x: i32) -> i32; // calling needs no unsafe
unsafe fn risky(p: *const u8); // calling needs unsafe
}
```
- **No references to `static mut`.** `&MY_STATIC_MUT` / `&mut MY_STATIC_MUT` is a
hard error (`static_mut_refs`). Use raw-ref operators instead:
```rust
static mut COUNTER: u32 = 0;
let p = &raw mut COUNTER; // *mut u32, not &mut
```
- **RPIT precise capturing (the big one).** In edition 2024, `-> impl Trait` in
return position captures **all** in-scope generic type, const, and lifetime
parameters by default. The old workaround of wrapping in a struct or adding
`+ 'a` to force capture is no longer needed. To *restrict* what is captured,
use a `use<...>` bound:
```rust
fn names(v: &[String]) -> impl Iterator<Item = &str> + use<'_> { /* ... */ }
fn no_capture<T>() -> impl Sized + use<> {} // capture nothing
```
Do NOT reach for the old lifetime-wrapper patterns; reach for `use<>`.
- **`if let` temporary scope.** Temporaries in the scrutinee of an
`if let … { } else { }` are dropped before the `else` branch runs (previously
they lived to the end of the whole construct). This fixes a class of deadlocks
where a lock guard was held across the `else`.
- **Tail-expression temporary scope.** In a block, temporaries in the final
tail expression are dropped *before* the block's local variables, changing
`Drop` ordering in some code.
- **Never-type fallback.** The `!` type now falls back to `!` (not `()`) in
certain diverging contexts; this can surface new inference results or
`never_type_fallback_flowing_into_unsafe` lints.
- **`gen` is a reserved keyword.** Use `r#gen` if you need it as an identifier.
- **Macro `expr` fragment** now also matches `const { … }` blocks and `_`.
---
## 2. New language features (by area)
### Control flow, patterns, bindings
- **Let chains** (1.88, **edition 2024 only**): chain `let` with `&&` in `if`/`while`:
```rust
if let Some(x) = a && let Ok(y) = parse(x) && y > 0 { /* ... */ }
```
This is stable now — do not claim it requires nightly.
- **`if let` guards** (1.95): a `let` pattern in a match-arm guard:
```rust
match val {
v if let Some(y) = lookup(v) => use_it(y),
_ => {}
}
```
- **Open-start ranges after unary ops** (1.87): `..EXPR` now parses after `!`, `-`, `*`.
### Async
- **Async closures** (1.85): `async || { … }` is stable, with the `AsyncFn` /
`AsyncFnMut` / `AsyncFnOnce` traits. No boxing/crate needed:
```rust
async fn run<F: AsyncFn(u32) -> u32>(f: F) -> u32 { f(1).await }
run(async |x| x + 1).await;
```
### Traits & generics
- **Trait upcasting** (1.86): coerce `dyn Sub` to `dyn Super` where `Sub: Super`:
```rust
let up: &dyn Super = sub_ref; // now stable
```
- **`use<>` precise capturing in trait RPIT** (1.87): `use<...>` bounds allowed on
return-position `impl Trait` in trait definitions.
- **Inferred const args** (1.89, `generic_arg_infer`): `_` may stand in for a
const generic argument, e.g. `let a: [_; _] = make();` style inference.
- **`#[repr(u128)]` / `#[repr(i128)]`** enums (1.89).
### unsafe / FFI / asm
- **Naked functions** (1.88): `#[unsafe(naked)]` with a `naked_asm!` body, stable.
- **C-variadic *declarations*** for more ABIs: `sysv64`/`win64`/`efiapi`/`aapcs`
(1.91) and `system` (1.93) `extern` fns may declare `...` variadics.
- **`asm_goto`** (1.87): `asm!` may jump to label blocks.
- **`asm_cfg`** (1.93): `#[cfg(...)]` allowed on individual `asm!` operands/lines.
- Many target features stabilized: **AVX-512** family (1.89), AES key-locker
(`kl`/`widekl`), `sha512`/`sm3`/`sm4`, `sse4a`/`tbm` (1.91), LoongArch & RISC-V
profiles, etc.
### Attributes, lints, macros
- **`#[diagnostic::do_not_recommend]`** (1.85): hide an impl from "consider
implementing" diagnostics.
- **`#[target_feature]` on safe fns** (1.86): safe functions may carry it.
- **`cfg_boolean_literals`** (1.88): `#[cfg(true)]` / `#[cfg(false)]`.
- **`cfg_select!`** (1.95): a `match`-like macro selecting a token tree by cfg.
---
## 3. Notable stdlib stabilizations (high-signal)
Slices / arrays:
- `<[T]>::as_array::<N>()` / `as_mut_array` → `Option<&[T; N]>` (1.93). Prefer
this over `try_into()` gymnastics for fixed-size views.
- `<[T]>::array_windows::<N>()` (1.94); `<[T]>::element_offset` (1.94).
Vec / collections:
- `Vec::push_mut`, `Vec::insert_mut` return `&mut T` to the new element (1.95);
same family on `VecDeque`/`LinkedList`.
- `Vec::into_raw_parts`, `String::into_raw_parts` (1.93).
- `VecDeque::pop_front_if` / `pop_back_if` (1.93).
- `Peekable::next_if_map` / `next_if_map_mut` (1.94).
- `btree_map::Entry::insert_entry` / `VacantEntry::insert_entry` (1.92).
Integers / math:
- **Strict arithmetic**: `{int}::strict_add/sub/mul/div/rem/neg/shl/shr/pow` etc.
(1.91) — like the `checked_*` family but panic on overflow instead of `None`.
- `<iN>::unchecked_neg/shl/shr`, `<uN>::unchecked_shl/shr` (1.93).
- `NonZero<u{N}>::div_ceil` (1.92).
- `f32`/`f64` consts `EULER_GAMMA`, `GOLDEN_RATIO`; `f32/f64::mul_add` const (1.94).
Sync / atomics:
- `Atomic{Bool,Ptr,Isize,Usize,…}::update` / `try_update` (1.95).
- `AtomicPtr::fetch_ptr_add/sub`, `fetch_byte_add/sub`, `fetch_or/and/xor` (1.91).
- `RwLockWriteGuard::downgrade` to a read guard (1.92).
Memory / smart pointers:
- `Box/Rc/Arc::new_zeroed` and `new_zeroed_slice` (1.92).
- `core::range` module with a `Copy`, cleanly-iterable `RangeInclusive` (1.95).
- `MaybeUninit<[T;N]>` ⇄ `[MaybeUninit<T>;N]` conversions; slice
`assume_init_ref/mut/drop`, `write_copy_of_slice` (1.93/1.95).
Misc:
- `bool: TryFrom<{integer}>` (1.95); `char::MAX_LEN_UTF8/UTF16` (1.93).
- `Duration::from_nanos_u128` (1.93); `Path::file_prefix` (1.91).
- A large number of previously-stable APIs are now usable in `const` contexts.
---
## 4. Cargo
- **2024 edition** is the default for new crates via `cargo new`.
- **Automatic cache garbage collection** (1.88): the global download/source cache
is pruned automatically; no manual cleanup script needed.
- **`build.build-dir`** stabilized (1.91): put intermediate artifacts in a
separate directory from the final `target/` outputs.
- **Multi-package publishing** (1.90): publish an entire workspace in one
`cargo publish` invocation, in dependency order.
- `cargo clean --workspace` (1.93); `config` top-level **`include`** key (1.94)
for composing config files; `CARGO_BIN_EXE_<crate>` available at runtime (1.94).
- Cargo parses TOML v1.1 manifests (1.94).
---
## 5. Cheat sheet — corrections a pre-2025 model commonly needs
| If you were about to write… | In current Rust (edition 2024) write… |
|---|---|
| `#[no_mangle]` | `#[unsafe(no_mangle)]` |
| `extern "C" { … }` (declaration) | `unsafe extern "C" { … }` |
| `&mut MY_STATIC_MUT` | `&raw mut MY_STATIC_MUT` |
| wrapper struct / `+ 'a` to constrain RPIT | `-> impl Trait + use<'a, T>` |
| "let chains need nightly" | stable in edition 2024 (since 1.88) |
| box/crate an async closure | `async || { … }` is stable (1.85) |
| `slice.try_into::<[T; N]>()` for a view | `slice.as_array::<N>()` |
| hand-rolled overflow-panicking add | `x.strict_add(y)` |
| "trait upcasting is unstable" | stable since 1.86 |
When in doubt, set the toolchain to a known version (`rustup show`) and let
`cargo check` / `cargo clippy` confirm. Edition-specific behavior depends on the
`edition` field in `Cargo.toml`, not the compiler version alone.