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.
This commit is contained in:
parent
9986d286b1
commit
a935e77f83
1 changed files with 207 additions and 0 deletions
207
config/agents/skills/rust-recent-features/SKILL.md
Normal file
207
config/agents/skills/rust-recent-features/SKILL.md
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
---
|
||||
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.
|
||||
Loading…
Add table
Add a link
Reference in a new issue