@@ -90,7 +90,7 @@ const IDIOMS_ENV_INTERNAL: &str = "__CARGO_FIX_IDIOMS";
9090const SYSROOT_INTERNAL : & str = "__CARGO_FIX_RUST_SRC" ;
9191
9292pub struct FixOptions {
93- pub edition : bool ,
93+ pub edition : Option < EditionFixMode > ,
9494 pub idioms : bool ,
9595 pub compile_opts : CompileOptions ,
9696 pub allow_dirty : bool ,
@@ -100,6 +100,46 @@ pub struct FixOptions {
100100 pub requested_lockfile_path : Option < PathBuf > ,
101101}
102102
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+
103143pub fn fix (
104144 gctx : & GlobalContext ,
105145 original_ws : & Workspace < ' _ > ,
@@ -109,13 +149,13 @@ pub fn fix(
109149
110150 let mut target_data =
111151 RustcTargetData :: new ( original_ws, & opts. compile_opts . build_config . requested_kinds ) ?;
112- if opts. edition {
152+ if let Some ( edition_mode ) = opts. edition {
113153 let specs = opts. compile_opts . spec . to_package_id_specs ( & original_ws) ?;
114154 let members: Vec < & Package > = original_ws
115155 . members ( )
116156 . filter ( |m| specs. iter ( ) . any ( |spec| spec. matches ( m. package_id ( ) ) ) )
117157 . collect ( ) ;
118- migrate_manifests ( original_ws, & members) ?;
158+ migrate_manifests ( original_ws, & members, edition_mode ) ?;
119159
120160 check_resolver_change ( & original_ws, & mut target_data, opts) ?;
121161 }
@@ -133,8 +173,8 @@ pub fn fix(
133173 wrapper. env ( BROKEN_CODE_ENV_INTERNAL , "1" ) ;
134174 }
135175
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 ( ) ) ;
138178 }
139179 if opts. idioms {
140180 wrapper. env ( IDIOMS_ENV_INTERNAL , "1" ) ;
@@ -248,7 +288,11 @@ fn check_version_control(gctx: &GlobalContext, opts: &FixOptions) -> CargoResult
248288 ) ;
249289}
250290
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 < ( ) > {
252296 // HACK: Duplicate workspace migration logic between virtual manifests and real manifests to
253297 // reduce multiple Migrating messages being reported for the same file to the user
254298 if matches ! ( ws. root_maybe( ) , MaybePackage :: Virtual ( _) ) {
@@ -259,7 +303,7 @@ fn migrate_manifests(ws: &Workspace<'_>, pkgs: &[&Package]) -> CargoResult<()> {
259303 . map ( |p| p. manifest ( ) . edition ( ) )
260304 . max ( )
261305 . unwrap_or_default ( ) ;
262- let prepare_for_edition = highest_edition . saturating_next ( ) ;
306+ let prepare_for_edition = edition_mode . next_edition ( highest_edition ) ;
263307 if highest_edition == prepare_for_edition
264308 || ( !prepare_for_edition. is_stable ( ) && !ws. gctx ( ) . nightly_features_allowed )
265309 {
@@ -304,7 +348,7 @@ fn migrate_manifests(ws: &Workspace<'_>, pkgs: &[&Package]) -> CargoResult<()> {
304348
305349 for pkg in pkgs {
306350 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 ) ;
308352 if existing_edition == prepare_for_edition
309353 || ( !prepare_for_edition. is_stable ( ) && !ws. gctx ( ) . nightly_features_allowed )
310354 {
@@ -1191,10 +1235,10 @@ impl FixArgs {
11911235 // ALLOWED: For the internal mechanism of `cargo fix` only.
11921236 // Shouldn't be set directly by anyone.
11931237 #[ 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 )
11981242 } ) ;
11991243
12001244 // ALLOWED: For the internal mechanism of `cargo fix` only.
0 commit comments