From 36530e29b535369ad7c7f99292e2aab405114ba4 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 15 Jul 2021 12:15:45 -0700 Subject: [PATCH 1/7] Update transitioning chapter. --- src/SUMMARY.md | 1 + src/editions/advanced-migrations.md | 173 ++++++++++++++++++ ...ng-an-existing-project-to-a-new-edition.md | 138 +++++--------- 3 files changed, 220 insertions(+), 92 deletions(-) create mode 100644 src/editions/advanced-migrations.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 2eae0132..6804ac2d 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -7,6 +7,7 @@ - [What are editions?](editions/index.md) - [Creating a new project](editions/creating-a-new-project.md) - [Transitioning an existing project to a new edition](editions/transitioning-an-existing-project-to-a-new-edition.md) + - [Advanced migrations](editions/advanced-migrations.md) ## Rust 2015 diff --git a/src/editions/advanced-migrations.md b/src/editions/advanced-migrations.md new file mode 100644 index 00000000..6b4aa10f --- /dev/null +++ b/src/editions/advanced-migrations.md @@ -0,0 +1,173 @@ +# Advanced migration strategies + +## How migrations work + +[`cargo fix --edition`][`cargo fix`] works by running the equivalent of [`cargo check`] on your project with special [lints] enabled which will detect code that may not compile in the next edition. +These lints include instructions on how to modify the code to make it compatible on both the current and the next edition. +`cargo fix` applies these changes to the source code, and then runs `cargo check` again to verify the fixes work. +If the fixes fail, then it will back out the changes and display a warning. + +The lints that `cargo fix --edition` apply are part of a [lint group]. +For example, when migrating from 2018 to 2021, Cargo uses the `rust-2021-compatibility` group of lints to fix the code. +Check the [Partial migration](#partial-migration-with-broken-code) section below for tips on using individual lints to help with migration. + +`cargo fix` may run `cargo check` multiple times. +For example, after applying one set of fixes, this may trigger new warnings which require further fixes. +Cargo repeats this until no new warnings are generated. + +## Migrating multiple configurations + +`cargo fix` can only work with a single configuration at a time. +If you use [Cargo features] or [conditional compilation], then you may need to run `cargo fix` multiple times with different flags. + +For example, if you have code that uses `#[cfg]` attributes to include different code for different platforms, you may need to run `cargo fix` with the `--target` option to fix for different targets. +This may require moving your code between machines if you don't have cross-compiling available. + +Similarly, if you have conditions on Cargo features, like `#[cfg(feature = "my-optional-thing")]`, it is recommended to use the `--all-features` flag to allow `cargo fix` to migrate all the code behind those feature gates. +If you want to migrate feature code individually, you can use the `--features` flag to migrate one at a time. + +## Migrating a large project or workspace + +You can migrate a large project incrementally to make the process easier if you run into problems. + +In a [Cargo workspace], each package defines its own edition, so the process naturally involves migrating one package at a time. + +Within a [Cargo package], you can either migrate the entire package at once, or migrate individual [Cargo targets] one at a time. +For example, if you have multiple binaries, tests, and examples, you can use specific target selection flags with `cargo fix --edition` to migrate just that one target. +By default, `cargo fix` uses `--all-targets`. + +For even more advanced cases, you can specify the edition for each individual target in `Cargo.toml` like this: + +```toml +[[bin]] +name = "my-binary" +edition = "2018" +``` + +This usually should not be required, but is an option if you have a lot of targets and are having difficulty migrating them all together. + +## Partial migration with broken code + +Sometimes the fixes suggested by the compiler may fail to work. +When this happens, Cargo will report a warning indicating what happened and what the error was. +However, by default it will automatically back out the changes it made. +It can be helpful to keep the code in the broken state and manually resolve the issue. +Some of the fixes may have been correct, and the broken fix maybe be *mostly* correct, but just need minor tweaking. + +In this situation, use the `--broken-code` option with `cargo fix` to tell Cargo not to back out the changes. +Then, you can go manually inspect the error and investigate what is needed to fix it. + +Another option to incrementally migrate a project is to apply individual fixes separately, one at a time. +You can do this by adding the individual lints as warnings, and then either running `cargo fix` (without the `--edition` flag) or using your editor or IDE to apply its suggestions if it supports "Quick Fixes". + +For example, the 2018 edition uses the [`keyword-idents`] lint to fix any conflicting keywords. +You can add `#![warn(keyword_idents)]` to the top of each crate (like at the top of `src/lib.rs` or `src/main.rs`). +Then, running `cargo fix` will apply just the suggestions for that lint. + +You can see the list of lints enabled for each edition in the [lint group] page, or run the `rustc -Whelp` command. + +## Migrating macros + +Some macros may require manual work to fix them for the next edition. +For example, a macro that generates syntax that only works on the previous edition, then `cargo fix` will not be able to fix it. + +This may be a problem for both [proc macros] and `macro_rules`-style macros. +`macro_rules` macros can be updated if the macro is used within the same crate, but if it is exported with `#[macro_export]`, then it may not be able to fix it. +Proc macros in general cannot be fixed at all. + +For example, this (contrived) macro won't get fixed when migrating to 2018. + +```rust +#[macro_export] +macro_rules! foo { + () => { + let dyn = 1; + println!("it is {}", dyn); + }; +} +``` + +If you don't have any tests that actually call this macro, then `cargo fix --edition` won't display any warnings or errors at all. +However, it won't work when called from another crate. + +If you have proc macros or exported macros, you are encouraged to test them by importing them in crates from multiple editions. +If you run into issues, you'll need to read through the chapters of this guide to understand how the code can be changed to work across all editions. + +### Macro hygiene + +Macros use a system called "edition hygiene" where the tokens within a macro are marked with which edition they come from. +This allows external macros to be called from crates of varying editions without needing to worry about which edition it is called from. + +Let's take a closer look at the example above that defines a `macro_rules` macro using `dyn` as an identifier. +If that macro was defined in a crate using the 2015 edition, then that macro works fine, even if it were called from a 2018 crate where `dyn` is a keyword and that would normally be a syntax error. +The `let dyn = 1;` tokens are marked as being from 2015, and the compiler will remember that wherever that code gets expanded. +The parser looks at the edition of the tokens to know how to interpret it. + +The problem arises when changing the edition to 2018 in the crate where it is defined. +Now, those tokens are tagged with the 2018 edition, and those will fail to parse. +However, since we never called the macro from our crate, `cargo fix --edition` never had a chance to inspect the macro and fix it. + + + +## Documentation tests + +At this time, `cargo fix` is not able to update [documentation tests]. +After updating the edition in `Cargo.toml`, you should run `cargo test` to ensure everything still passes. +If your documentation tests use syntax that is not supported in the new edition, you will need to update them manually. + +In rare cases, you can manually set the edition for each test. +For example, you can use the [`edition2018` annotation][rustdoc-annotation] on the triple backticks to tell `rustdoc` which edition to use. + +## Writing idiomatic code in a new edition + +Editions are not only about new features and removing old ones. +In any programming language, idioms change over time, and Rust is no exception. +While old code will continue to compile, it might be written with different idioms today. + +For example, in Rust 2015, external crates must be listed with `extern crate` like this: + +```rust,ignore +// src/lib.rs +extern crate rand; +``` + +In Rust 2018, it is [no longer necessary](../rust-2018/path-changes.md#no-more-extern-crate) to include these items. + +`cargo fix` has the `--edition-idioms` option to automatically transition some of these idioms to the new syntax. + +> **Warning**: The current *"idiom lints"* are known to have some problems. +> They may make incorrect suggestions which may fail to compile. +> The current lints are: +> * Edition 2018: +> * [`unused-extern-crates`] +> * [`explicit-outlives-requirements`] +> * Edition 2021 does not have any idiom lints. +> +> The following instructions are recommended only for the intrepid who are willing to work through a few compiler/Cargo bugs! +> If you run into problems, you can try the `--broken-code` option [described above](#partial-migration-with-broken-code) to make as much progress as possible, and then resolve the remaining issues manually. + +With that out of the way, we can instruct Cargo to fix our code snippet with: + +```console +cargo fix --edition-idioms +``` + +Afterwards, the line with `extern crate rand;` in `src/lib.rs` will be removed. + +We're now more idiomatic, and we didn't have to fix our code manually! + +[`cargo check`]: ../../cargo/commands/cargo-check.html +[`cargo fix`]: ../../cargo/commands/cargo-fix.html +[`explicit-outlives-requirements`]: ../../rustc/lints/listing/allowed-by-default.html#explicit-outlives-requirements +[`keyword-idents`]: ../../rustc/lints/listing/allowed-by-default.html#keyword-idents +[`unused-extern-crates`]: ../../rustc/lints/listing/allowed-by-default.html#unused-extern-crates +[Cargo features]: ../../cargo/reference/features.html +[Cargo package]: ../../cargo/reference/manifest.html#the-package-section +[Cargo targets]: ../../cargo/reference/cargo-targets.html +[Cargo workspace]: ../../cargo/reference/workspaces.html +[conditional compilation]: ../../reference/conditional-compilation.html +[documentation tests]: ../../rustdoc/documentation-tests.html +[lint group]: ../../rustc/lints/groups.html +[lints]: ../../rustc/lints/index.html +[proc macros]: ../../reference/procedural-macros.html +[rustdoc-annotation]: ../../rustdoc/documentation-tests.html#attributes diff --git a/src/editions/transitioning-an-existing-project-to-a-new-edition.md b/src/editions/transitioning-an-existing-project-to-a-new-edition.md index beb23604..6732837e 100644 --- a/src/editions/transitioning-an-existing-project-to-a-new-edition.md +++ b/src/editions/transitioning-an-existing-project-to-a-new-edition.md @@ -1,37 +1,54 @@ # Transitioning an existing project to a new edition -New editions might change the way you write Rust – they add new syntax, -language, and library features, and also remove features. For example, `try`, -`async`, and `await` are keywords in Rust 2018, but not Rust 2015. If you -have a project that's using Rust 2015, and you'd like to use Rust 2018 for it -instead, there's a few steps that you need to take. +Rust includes tooling to automatically transition a project from one edition to the next. +It will update your source code so that it is compatible with the next edition. +Briefly, the steps to update to the next edition are: + +1. Run `cargo fix --edition` +2. Edit `Cargo.toml` and set the `edition` field to the next edition, for example `edition = "2021"` +3. Run `cargo build` or `cargo test` to verify the fixes worked. + + +> If you are migrating from 2018 to 2021, the steps are slightly different because 2021 is not yet stabilized, and is only available on the [nightly channel]. +> The steps to follow are: +> +> 1. Install the most recent nightly: `rustup update nightly`. +> 2. Run `cargo +nightly fix --edition`. +> 3. Edit `Cargo.toml` and place `cargo-features = ["edition2021"]` at the top (above `[package]`), and change the edition field to say `edition = "2021"`. +> 4. Run `cargo +nightly check` to verify it now works in the new edition. + +The following sections dig into the details of these steps, and some of the issues you may encounter along the way. > It's our intention that the migration to new editions is as smooth an > experience as possible. If it's difficult for you to upgrade to the latest edition, > we consider that a bug. If you run into problems with this process, please -> [file a bug](https://github.com/rust-lang/rust/issues/new). Thank you! +> [file a bug](https://github.com/rust-lang/rust/issues/new/choose). Thank you! + +## Starting the migration + +As an example, let's take a look at transitioning from the 2015 edition to the 2018 edition. +The steps are essentially the same when transitioning to other editions like 2021. -Here's an example. Imagine we have a crate that has this code in -`src/lib.rs`: +Imagine we have a crate that has this code in `src/lib.rs`: ```rust trait Foo { - fn foo(&self, Box); + fn foo(&self, i32); } ``` -This code uses an anonymous parameter, that `Box`. This is [not +This code uses an anonymous parameter, that `i32`. This is [not supported in Rust 2018](../rust-2018/trait-system/no-anon-params.md), and so this would fail to compile. Let's get this code up to date! ## Updating your code to be compatible with the new edition -Your code may or may not use features that are incompatible with the new -edition. In order to help transition to Rust 2018, we've included a new -subcommand with Cargo. To start, let's run it: +Your code may or may not use features that are incompatible with the new edition. +In order to help transition to the next edition, Cargo includes the [`cargo fix`] subcommand to automatically update your source code. +To start, let's run it: ```console -> cargo fix --edition +cargo fix --edition ``` This will check your code, and automatically fix any issues that it can. @@ -39,106 +56,43 @@ Let's look at `src/lib.rs` again: ```rust trait Foo { - fn foo(&self, _: Box); + fn foo(&self, _: i32); } ``` -It's re-written our code to introduce a parameter name for that trait object. +It's re-written our code to introduce a parameter name for that `i32` value. In this case, since it had no name, `cargo fix` will replace it with `_`, which is conventional for unused variables. `cargo fix` can't always fix your code automatically. If `cargo fix` can't fix something, it will print the warning that it cannot fix -to the console. If you see one of these warnings, you'll have to update your code -manually. See the corresponding section of this guide for help, and if you have -problems, please seek help at the [user's forums](https://users.rust-lang.org/). - -Keep running `cargo fix --edition` until you have no more warnings. - -Congrats! Your code is now valid in both Rust 2015 and Rust 2018! +to the console. If you see one of these warnings, you'll have to update your code manually. +See the [Advanced migration strategies] chapter for more on working with the migration process, and read the chapters in this guide which explain which changes are needed. +If you have problems, please seek help at the [user's forums](https://users.rust-lang.org/). ## Enabling the new edition to use new features In order to use some new features, you must explicitly opt in to the new -edition. Once you're ready to commit, change your `Cargo.toml` to add the new +edition. Once you're ready to continue, change your `Cargo.toml` to add the new `edition` key/value pair. For example: ```toml [package] name = "foo" version = "0.1.0" -authors = ["Your Name "] edition = "2018" ``` If there's no `edition` key, Cargo will default to Rust 2015. But in this case, -we've chosen `2018`, and so our code is compiling with Rust 2018! - -## Writing idiomatic code in a new edition - -Editions are not only about new features and removing old ones. In any programming -language, idioms change over time, and Rust is no exception. While old code -will continue to compile, it might be written with different idioms today. - -Our sample code contains an outdated idiom. Here it is again: - -```rust -trait Foo { - fn foo(&self, _: Box); -} -``` - -In Rust 2018, it's considered idiomatic to use the [`dyn` -keyword](../rust-2018/trait-system/dyn-trait-for-trait-objects.md) for -trait objects. - -Eventually, we want `cargo fix` to fix all these idioms automatically in the same -manner we did for upgrading to the 2018 edition. **Currently, -though, the *"idiom lints"* are not ready for widespread automatic fixing.** The -compiler isn't making `cargo fix`-compatible suggestions in many cases right -now, and it is making incorrect suggestions in others. Enabling the idiom lints, -even with `cargo fix`, is likely to leave your crate either broken or with many -warnings still remaining. +we've chosen `2018`, and so our code will compile with Rust 2018! -We have plans to make these idiom migrations a seamless part of the Rust 2018 -experience, but we're not there yet. As a result the following instructions are -recommended only for the intrepid who are willing to work through a few -compiler/Cargo bugs! +The next step is to test your project on the new edition. +Run your project tests to verify that everything still works, such as running [`cargo test`]. +If new warnings are issued, you may want to consider running `cargo fix` again (without the `--edition` flag) to apply any suggestions given by the compiler. -With that out of the way, we can instruct Cargo to fix our code snippet with: - -```console -$ cargo fix --edition-idioms -``` - -Afterwards, `src/lib.rs` looks like this: - -```rust -trait Foo { - fn foo(&self, _: Box); -} -``` - -We're now more idiomatic, and we didn't have to fix our code manually! - -Note that `cargo fix` may still not be able to automatically update our code. -If `cargo fix` can't fix something, it will print a warning to the console, and -you'll have to fix it manually. - -As mentioned before, there are known bugs around the idiom lints which -means they're not all ready for prime time yet. You may get a scary-looking -warning to report a bug to Cargo, which happens whenever a fix proposed by -`rustc` actually caused code to stop compiling by accident. If you'd like `cargo -fix` to make as much progress as possible, even if it causes code to stop -compiling, you can execute: - -```console -$ cargo fix --edition-idioms --broken-code -``` - -This will instruct `cargo fix` to apply automatic suggestions regardless of -whether they work or not. Like usual, you'll see the compilation result after -all fixes are applied. If you notice anything wrong or unusual, please feel free -to report an issue to Cargo and we'll help prioritize and fix it. +Congrats! Your code is now valid in both Rust 2015 and Rust 2018! -Enjoy the new edition! +[`cargo fix`]: ../../cargo/commands/cargo-fix.html +[`cargo test`]: ../../cargo/commands/cargo-test.html +[Advanced migration strategies]: advanced-migrations.md +[nightly channel]: ../../book/appendix-07-nightly-rust.html From 2187a653dbf8306b110f393039f2b39fb7d276bc Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 15 Jul 2021 16:35:49 -0700 Subject: [PATCH 2/7] Add note emphasizing why the migration does a "compiles on both" strategy. --- src/editions/advanced-migrations.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/editions/advanced-migrations.md b/src/editions/advanced-migrations.md index 6b4aa10f..2d741d7a 100644 --- a/src/editions/advanced-migrations.md +++ b/src/editions/advanced-migrations.md @@ -4,9 +4,12 @@ [`cargo fix --edition`][`cargo fix`] works by running the equivalent of [`cargo check`] on your project with special [lints] enabled which will detect code that may not compile in the next edition. These lints include instructions on how to modify the code to make it compatible on both the current and the next edition. -`cargo fix` applies these changes to the source code, and then runs `cargo check` again to verify the fixes work. +`cargo fix` applies these changes to the source code, and then runs `cargo check` again to verify that the fixes work. If the fixes fail, then it will back out the changes and display a warning. +Changing the code to be simultaneously compatible with both the current and next edition makes it easier to incrementally migrate the code. +If the automated migration does not completely succeed, or requires manual help, you can iterate while staying on the original edition before changing `Cargo.toml` to use the next edition. + The lints that `cargo fix --edition` apply are part of a [lint group]. For example, when migrating from 2018 to 2021, Cargo uses the `rust-2021-compatibility` group of lints to fix the code. Check the [Partial migration](#partial-migration-with-broken-code) section below for tips on using individual lints to help with migration. From cacf1c4e7f3209fd0fc12f5e8eb96619bb95bace Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 15 Jul 2021 16:45:45 -0700 Subject: [PATCH 3/7] Add note about generated code. --- src/editions/advanced-migrations.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/editions/advanced-migrations.md b/src/editions/advanced-migrations.md index 2d741d7a..9e470b2c 100644 --- a/src/editions/advanced-migrations.md +++ b/src/editions/advanced-migrations.md @@ -121,6 +121,11 @@ If your documentation tests use syntax that is not supported in the new edition, In rare cases, you can manually set the edition for each test. For example, you can use the [`edition2018` annotation][rustdoc-annotation] on the triple backticks to tell `rustdoc` which edition to use. +## Generated code + +Another area where the automated fixes cannot apply is if you have a build script which generates Rust code at compile time (see [Code generation] for an example). +In this situation, if you end up with code that doesn't work in the next edition, you will need to manually change the build script to generate code that is compatible. + ## Writing idiomatic code in a new edition Editions are not only about new features and removing old ones. @@ -168,6 +173,7 @@ We're now more idiomatic, and we didn't have to fix our code manually! [Cargo package]: ../../cargo/reference/manifest.html#the-package-section [Cargo targets]: ../../cargo/reference/cargo-targets.html [Cargo workspace]: ../../cargo/reference/workspaces.html +[Code generation]: ../../cargo/reference/build-script-examples.html#code-generation [conditional compilation]: ../../reference/conditional-compilation.html [documentation tests]: ../../rustdoc/documentation-tests.html [lint group]: ../../rustc/lints/groups.html From 73ae835ef57eebae02a53210edf9458730ae97c1 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 15 Jul 2021 17:16:27 -0700 Subject: [PATCH 4/7] Add a section on migrating without Cargo. --- src/editions/advanced-migrations.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/editions/advanced-migrations.md b/src/editions/advanced-migrations.md index 9e470b2c..4819c208 100644 --- a/src/editions/advanced-migrations.md +++ b/src/editions/advanced-migrations.md @@ -126,6 +126,23 @@ For example, you can use the [`edition2018` annotation][rustdoc-annotation] on t Another area where the automated fixes cannot apply is if you have a build script which generates Rust code at compile time (see [Code generation] for an example). In this situation, if you end up with code that doesn't work in the next edition, you will need to manually change the build script to generate code that is compatible. +## Migrating non-Cargo projects + +If your project is not using Cargo as a build system, it may still be possible to make use of the automated lints to assist migrating to the next build system. +You can enable the migration lints as described above by enabling the appropriate [lint group]. +For example, you can use the `#![warn(rust_2021_compatibility)]` attribute or the `-Wrust-2021-compatibility` [CLI flag]. + +The next step is to apply those lints to your code. +There are several options here: + +* Manually read the warnings and apply the suggestions recommended by the compiler. +* Use an editor or IDE that supports automatically applying suggestions. + For example, [Visual Studio Code] with the [Rust Analyzer extension] has the ability to use the "Quick Fix" links to automatically apply suggestions. + Many other editors and IDEs have similar functionality. +* Write a migration tool using the [`rustfix`] library. + This is the library that Cargo uses internally to take the [JSON messages] from the compiler and modify the source code. + Check the [`examples` directory][rustfix-examples] for examples of how to use the library. + ## Writing idiomatic code in a new edition Editions are not only about new features and removing old ones. @@ -168,15 +185,21 @@ We're now more idiomatic, and we didn't have to fix our code manually! [`cargo fix`]: ../../cargo/commands/cargo-fix.html [`explicit-outlives-requirements`]: ../../rustc/lints/listing/allowed-by-default.html#explicit-outlives-requirements [`keyword-idents`]: ../../rustc/lints/listing/allowed-by-default.html#keyword-idents +[`rustfix`]: https://github.com/rust-lang/rustfix [`unused-extern-crates`]: ../../rustc/lints/listing/allowed-by-default.html#unused-extern-crates [Cargo features]: ../../cargo/reference/features.html [Cargo package]: ../../cargo/reference/manifest.html#the-package-section [Cargo targets]: ../../cargo/reference/cargo-targets.html [Cargo workspace]: ../../cargo/reference/workspaces.html +[CLI flag]: ../../rustc/lints/levels.html#via-compiler-flag [Code generation]: ../../cargo/reference/build-script-examples.html#code-generation [conditional compilation]: ../../reference/conditional-compilation.html [documentation tests]: ../../rustdoc/documentation-tests.html +[JSON messages]: ../../rustc/json.html [lint group]: ../../rustc/lints/groups.html [lints]: ../../rustc/lints/index.html [proc macros]: ../../reference/procedural-macros.html +[Rust Analyzer extension]: https://marketplace.visualstudio.com/items?itemName=matklad.rust-analyzer [rustdoc-annotation]: ../../rustdoc/documentation-tests.html#attributes +[rustfix-examples]: https://github.com/rust-lang/rustfix/tree/master/examples +[Visual Studio Code]: https://code.visualstudio.com/ From 02583b6faaccb3f9eb0877225f923388e0b460f8 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Fri, 16 Jul 2021 16:25:09 -0700 Subject: [PATCH 5/7] Mention --force-warns. --- src/editions/advanced-migrations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/editions/advanced-migrations.md b/src/editions/advanced-migrations.md index 4819c208..321bc212 100644 --- a/src/editions/advanced-migrations.md +++ b/src/editions/advanced-migrations.md @@ -130,7 +130,7 @@ In this situation, if you end up with code that doesn't work in the next edition If your project is not using Cargo as a build system, it may still be possible to make use of the automated lints to assist migrating to the next build system. You can enable the migration lints as described above by enabling the appropriate [lint group]. -For example, you can use the `#![warn(rust_2021_compatibility)]` attribute or the `-Wrust-2021-compatibility` [CLI flag]. +For example, you can use the `#![warn(rust_2021_compatibility)]` attribute or the `-Wrust-2021-compatibility` or `--force-warns=rust-2021-compatibility` [CLI flag]. The next step is to apply those lints to your code. There are several options here: From 890abe630f54b25ccf697100b80b86a3e9fb2455 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 19 Jul 2021 11:13:54 -0700 Subject: [PATCH 6/7] Clarify "Migrating macros". --- src/editions/advanced-migrations.md | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/editions/advanced-migrations.md b/src/editions/advanced-migrations.md index 321bc212..9cbc5a2c 100644 --- a/src/editions/advanced-migrations.md +++ b/src/editions/advanced-migrations.md @@ -72,13 +72,13 @@ You can see the list of lints enabled for each edition in the [lint group] page, ## Migrating macros Some macros may require manual work to fix them for the next edition. -For example, a macro that generates syntax that only works on the previous edition, then `cargo fix` will not be able to fix it. +For example, `cargo fix --edition` may not be able to automatically fix a macro that generates syntax that does not work in the next edition. This may be a problem for both [proc macros] and `macro_rules`-style macros. -`macro_rules` macros can be updated if the macro is used within the same crate, but if it is exported with `#[macro_export]`, then it may not be able to fix it. -Proc macros in general cannot be fixed at all. +`macro_rules` macros can sometimes be automatically updated if the macro is used within the same crate, but there are several situations where it cannot. +Proc macros in general cannot be automatically fixed at all. -For example, this (contrived) macro won't get fixed when migrating to 2018. +For example, if we migrate a crate containing this (contrived) macro `foo` from 2015 to 2018, `foo` would not be automatically fixed. ```rust #[macro_export] @@ -90,10 +90,15 @@ macro_rules! foo { } ``` -If you don't have any tests that actually call this macro, then `cargo fix --edition` won't display any warnings or errors at all. -However, it won't work when called from another crate. +When this macro is defined in a 2015 crate, it can be used from a crate of any other edition due to macro hygiene (discussed below). +In 2015, `dyn` is a normal identifier and can be used without restriction. -If you have proc macros or exported macros, you are encouraged to test them by importing them in crates from multiple editions. +However, in 2018, `dyn` is no longer a valid identifier. +When using `cargo fix --edition` to migrate to 2018, Cargo won't display any warnings or errors at all. +However, `foo` won't work when called from any crate. + +If you have macros, you are encouraged to make sure you have tests that fully cover the macro's syntax. +You may also want to test the macros by importing and using them in crates from multiple editions, just to ensure it works correctly everywhere. If you run into issues, you'll need to read through the chapters of this guide to understand how the code can be changed to work across all editions. ### Macro hygiene From 7ab6ad2378c5c6fd1c5502e11960b44f2f2af5b6 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Mon, 19 Jul 2021 20:03:51 -0700 Subject: [PATCH 7/7] Fix flub. --- src/editions/advanced-migrations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/editions/advanced-migrations.md b/src/editions/advanced-migrations.md index 9cbc5a2c..b804ae64 100644 --- a/src/editions/advanced-migrations.md +++ b/src/editions/advanced-migrations.md @@ -133,7 +133,7 @@ In this situation, if you end up with code that doesn't work in the next edition ## Migrating non-Cargo projects -If your project is not using Cargo as a build system, it may still be possible to make use of the automated lints to assist migrating to the next build system. +If your project is not using Cargo as a build system, it may still be possible to make use of the automated lints to assist migrating to the next edition. You can enable the migration lints as described above by enabling the appropriate [lint group]. For example, you can use the `#![warn(rust_2021_compatibility)]` attribute or the `-Wrust-2021-compatibility` or `--force-warns=rust-2021-compatibility` [CLI flag].