Rust 2024 Edition

Migration with cargo fix --edition

cargo fix --edition is Cargo's automated migration tool that inspects your package under its current edition, enables the target edition's compatibility lint group (rust-2024-compatibility), and rewrites your source files in place so they compile cleanly under both the old and new editions.

4-Step Automated Edition Migration Workflow:

  Step 1: Verify clean working tree & passing tests on current edition (`edition = "2021"`)
          `cargo test --workspace --all-targets --all-features`
                               |
                               v
  Step 2: Run automated edition migration rewrites
          `cargo fix --edition --workspace --all-targets --all-features`
                               |
                               v
  Step 3: Update `Cargo.toml` to `edition = "2024"`
          (and `resolver = "3"` if specified in a virtual `[workspace]`)
                               |
                               v
  Step 4: Format & verify under Rust 2024
          `cargo fmt --all` && `cargo test --workspace --all-targets --all-features`

Lints Included in the rust-2024-compatibility Group

When you run cargo fix --edition, rustc activates the rust-2024-compatibility lint group and automatically applies code transformations for each lint:

Compatibility Lint What cargo fix --edition Rewrites Automatically
missing_unsafe_on_extern Rewrites extern "C" { ... } to unsafe extern "C" { ... }.
unsafe_attr_outside_unsafe Rewrites #[no_mangle], #[export_name = "..."], and #[link_section = "..."] to #[unsafe(no_mangle)], etc.
deprecated_safe_2024 Wraps calls to std::env::set_var and std::env::remove_var in unsafe { ... } blocks (if not already inside one).
keyword_idents_2024 Rewrites any variable, function, or type named gen to the raw identifier r#gen.
impl_trait_overcaptures Appends + use<...> to -> impl Trait return types where existing call sites relied on Rust 2021's narrower lifetime capture rules!
Match Ergonomics Migration Rewrites patterns with redundant ref / mut under reference binding modes to explicit & / * forms.
boxed_slice_into_iter Rewrites boxed_slice.into_iter() calls in pre-2024 code to boxed_slice.iter() so their item type stays &T (since Box<[T]>::into_iter() now yields T by value in Rust 2024!).
never_type_fallback_flowing_into_unsafe Adds explicit type annotations (::<()>) where !-to-() fallback changes affect type inference.

Example Before and After cargo fix --edition

// BEFORE running `cargo fix --edition` (in a Rust 2021 crate):
//
// #[no_mangle]
// pub extern "C" fn gen(x: i32) -> i32 {
//     let boxed: Box<[i32]> = Box::new([1, 2, 3]);
//     boxed.into_iter().map(|&v| v + x).sum()
// }

// AFTER running `cargo fix --edition` (valid in BOTH Rust 2021 and Rust 2024!):
#[unsafe(no_mangle)]
pub extern "C" fn r#gen(x: i32) -> i32 {
    let boxed: Box<[i32]> = Box::new([1, 2, 3]);
    // In Rust 2024, `Box<[T]>` implements `IntoIterator` by VALUE (`Item = i32`)!
    boxed.into_iter().map(|v| v + x).sum()
}

fn main() {
    println!("Result of migrated function: {}", r#gen(10));
}
Result of migrated function: 36

Handling Feature-Gated and Platform-Specific Code During Migration

Because cargo fix --edition only rewrites code that rustc actually compiles during the invocation:

  1. Always pass --all-targets --all-features (cargo fix --edition --all-targets --all-features) so unit tests, integration tests, examples, benchmarks, and optional feature blocks are all migrated.
  2. If your crate has platform-specific modules (#[cfg(windows)] vs #[cfg(unix)]), run cargo check --target <triple> (or rely on CI across Linux, macOS, and Windows) after switching to edition = "2024" to verify all platform branches.