@@ -90,7 +90,7 @@ const IDIOMS_ENV_INTERNAL: &str = "__CARGO_FIX_IDIOMS";
90
90
const SYSROOT_INTERNAL : & str = "__CARGO_FIX_RUST_SRC" ;
91
91
92
92
pub struct FixOptions {
93
- pub edition : bool ,
93
+ pub edition : Option < EditionFixMode > ,
94
94
pub idioms : bool ,
95
95
pub compile_opts : CompileOptions ,
96
96
pub allow_dirty : bool ,
@@ -100,6 +100,46 @@ pub struct FixOptions {
100
100
pub requested_lockfile_path : Option < PathBuf > ,
101
101
}
102
102
103
+ /// The behavior of `--edition` migration.
104
+ #[ derive( Clone , Copy ) ]
105
+ pub enum EditionFixMode {
106
+ /// Migrates the package from the current edition to the next.
107
+ ///
108
+ /// This is the normal (stable) behavior of `--edition`.
109
+ NextRelative ,
110
+ /// Migrates to a specific edition.
111
+ ///
112
+ /// This is used by `-Zfix-edition` to force a specific edition like
113
+ /// `future`, which does not have a relative value.
114
+ OverrideSpecific ( Edition ) ,
115
+ }
116
+
117
+ impl EditionFixMode {
118
+ /// Returns the edition to use for the given current edition.
119
+ pub fn next_edition ( & self , current_edition : Edition ) -> Edition {
120
+ match self {
121
+ EditionFixMode :: NextRelative => current_edition. saturating_next ( ) ,
122
+ EditionFixMode :: OverrideSpecific ( edition) => * edition,
123
+ }
124
+ }
125
+
126
+ /// Serializes to a string.
127
+ fn to_string ( & self ) -> String {
128
+ match self {
129
+ EditionFixMode :: NextRelative => "1" . to_string ( ) ,
130
+ EditionFixMode :: OverrideSpecific ( edition) => edition. to_string ( ) ,
131
+ }
132
+ }
133
+
134
+ /// Deserializes from the given string.
135
+ fn from_str ( s : & str ) -> EditionFixMode {
136
+ match s {
137
+ "1" => EditionFixMode :: NextRelative ,
138
+ edition => EditionFixMode :: OverrideSpecific ( edition. parse ( ) . unwrap ( ) ) ,
139
+ }
140
+ }
141
+ }
142
+
103
143
pub fn fix (
104
144
gctx : & GlobalContext ,
105
145
original_ws : & Workspace < ' _ > ,
@@ -109,13 +149,13 @@ pub fn fix(
109
149
110
150
let mut target_data =
111
151
RustcTargetData :: new ( original_ws, & opts. compile_opts . build_config . requested_kinds ) ?;
112
- if opts. edition {
152
+ if let Some ( edition_mode ) = opts. edition {
113
153
let specs = opts. compile_opts . spec . to_package_id_specs ( & original_ws) ?;
114
154
let members: Vec < & Package > = original_ws
115
155
. members ( )
116
156
. filter ( |m| specs. iter ( ) . any ( |spec| spec. matches ( m. package_id ( ) ) ) )
117
157
. collect ( ) ;
118
- migrate_manifests ( original_ws, & members) ?;
158
+ migrate_manifests ( original_ws, & members, edition_mode ) ?;
119
159
120
160
check_resolver_change ( & original_ws, & mut target_data, opts) ?;
121
161
}
@@ -133,8 +173,8 @@ pub fn fix(
133
173
wrapper. env ( BROKEN_CODE_ENV_INTERNAL , "1" ) ;
134
174
}
135
175
136
- if opts. edition {
137
- wrapper. env ( EDITION_ENV_INTERNAL , "1" ) ;
176
+ if let Some ( mode ) = & opts. edition {
177
+ wrapper. env ( EDITION_ENV_INTERNAL , mode . to_string ( ) ) ;
138
178
}
139
179
if opts. idioms {
140
180
wrapper. env ( IDIOMS_ENV_INTERNAL , "1" ) ;
@@ -248,7 +288,11 @@ fn check_version_control(gctx: &GlobalContext, opts: &FixOptions) -> CargoResult
248
288
) ;
249
289
}
250
290
251
- fn migrate_manifests ( ws : & Workspace < ' _ > , pkgs : & [ & Package ] ) -> CargoResult < ( ) > {
291
+ fn migrate_manifests (
292
+ ws : & Workspace < ' _ > ,
293
+ pkgs : & [ & Package ] ,
294
+ edition_mode : EditionFixMode ,
295
+ ) -> CargoResult < ( ) > {
252
296
// HACK: Duplicate workspace migration logic between virtual manifests and real manifests to
253
297
// reduce multiple Migrating messages being reported for the same file to the user
254
298
if matches ! ( ws. root_maybe( ) , MaybePackage :: Virtual ( _) ) {
@@ -259,7 +303,7 @@ fn migrate_manifests(ws: &Workspace<'_>, pkgs: &[&Package]) -> CargoResult<()> {
259
303
. map ( |p| p. manifest ( ) . edition ( ) )
260
304
. max ( )
261
305
. unwrap_or_default ( ) ;
262
- let prepare_for_edition = highest_edition . saturating_next ( ) ;
306
+ let prepare_for_edition = edition_mode . next_edition ( highest_edition ) ;
263
307
if highest_edition == prepare_for_edition
264
308
|| ( !prepare_for_edition. is_stable ( ) && !ws. gctx ( ) . nightly_features_allowed )
265
309
{
@@ -304,7 +348,7 @@ fn migrate_manifests(ws: &Workspace<'_>, pkgs: &[&Package]) -> CargoResult<()> {
304
348
305
349
for pkg in pkgs {
306
350
let existing_edition = pkg. manifest ( ) . edition ( ) ;
307
- let prepare_for_edition = existing_edition . saturating_next ( ) ;
351
+ let prepare_for_edition = edition_mode . next_edition ( existing_edition ) ;
308
352
if existing_edition == prepare_for_edition
309
353
|| ( !prepare_for_edition. is_stable ( ) && !ws. gctx ( ) . nightly_features_allowed )
310
354
{
@@ -1191,10 +1235,10 @@ impl FixArgs {
1191
1235
// ALLOWED: For the internal mechanism of `cargo fix` only.
1192
1236
// Shouldn't be set directly by anyone.
1193
1237
#[ allow( clippy:: disallowed_methods) ]
1194
- let prepare_for_edition = env:: var ( EDITION_ENV_INTERNAL ) . ok ( ) . map ( |_ | {
1195
- enabled_edition
1196
- . unwrap_or ( Edition :: Edition2015 )
1197
- . saturating_next ( )
1238
+ let prepare_for_edition = env:: var ( EDITION_ENV_INTERNAL ) . ok ( ) . map ( |v | {
1239
+ let enabled_edition = enabled_edition . unwrap_or ( Edition :: Edition2015 ) ;
1240
+ let mode = EditionFixMode :: from_str ( & v ) ;
1241
+ mode . next_edition ( enabled_edition )
1198
1242
} ) ;
1199
1243
1200
1244
// ALLOWED: For the internal mechanism of `cargo fix` only.
0 commit comments