diff --git a/src/cargo/core/compiler/future_incompat.rs b/src/cargo/core/compiler/future_incompat.rs index f184b472c3a..8cc3878fc13 100644 --- a/src/cargo/core/compiler/future_incompat.rs +++ b/src/cargo/core/compiler/future_incompat.rs @@ -70,6 +70,8 @@ pub struct FutureIncompatReport { /// Structure used for collecting reports in-memory. pub struct FutureIncompatReportPackage { pub package_id: PackageId, + /// Whether or not this is a local package, or a remote dependency. + pub is_local: bool, pub items: Vec, } @@ -140,16 +142,10 @@ impl OnDiskReports { mut self, ws: &Workspace<'_>, suggestion_message: String, - per_package_reports: &[FutureIncompatReportPackage], + per_package: BTreeMap, ) -> u32 { - let per_package = render_report(per_package_reports); - - if let Some(existing_report) = self - .reports - .iter() - .find(|existing| existing.per_package == per_package) - { - return existing_report.id; + if let Some(existing_id) = self.has_report(&per_package) { + return existing_id; } let report = OnDiskReport { @@ -189,6 +185,14 @@ impl OnDiskReports { saved_id } + /// Returns the ID of a report if it is already on disk. + fn has_report(&self, rendered_per_package: &BTreeMap) -> Option { + self.reports + .iter() + .find(|existing| &existing.per_package == rendered_per_package) + .map(|report| report.id) + } + /// Loads the on-disk reports. pub fn load(ws: &Workspace<'_>) -> CargoResult { let report_file = match ws.build_dir().open_ro_shared( @@ -408,7 +412,14 @@ pub fn save_and_display_report( OnDiskReports::default() } }; - let report_id = current_reports.next_id; + + let rendered_report = render_report(per_package_future_incompat_reports); + + // If the report is already on disk, then it will reuse the same ID, + // otherwise prepare for the next ID. + let report_id = current_reports + .has_report(&rendered_report) + .unwrap_or(current_reports.next_id); // Get a list of unique and sorted package name/versions. let package_ids: BTreeSet<_> = per_package_future_incompat_reports @@ -461,11 +472,18 @@ You may want to consider updating them to a newer version to see if the issue ha .collect::>() .join("\n"); - let suggestion_message = format!( - " + let all_is_local = per_package_future_incompat_reports + .iter() + .all(|report| report.is_local); + + let suggestion_message = if all_is_local { + String::new() + } else { + format!( + " To solve this problem, you can try the following approaches: -{update_message} +{update_message}\ - If the issue is not solved by updating the dependencies, a fix has to be implemented by those dependencies. You can help with that by notifying the maintainers of this problem (e.g. by creating a bug report) or by proposing a @@ -476,19 +494,19 @@ fix to the maintainers (e.g. by creating a pull request): section in `Cargo.toml` to use your own version of the dependency. For more information, see: https://doc.rust-lang.org/cargo/reference/overriding-dependencies.html#the-patch-section - ", - upstream_info = upstream_info, - update_message = update_message, - ); +", + upstream_info = upstream_info, + update_message = update_message, + ) + }; - let saved_report_id = current_reports.save_report( - bcx.ws, - suggestion_message.clone(), - per_package_future_incompat_reports, - ); + let saved_report_id = + current_reports.save_report(bcx.ws, suggestion_message.clone(), rendered_report); if bcx.build_config.future_incompat_report { - drop(bcx.gctx.shell().note(&suggestion_message)); + if !suggestion_message.is_empty() { + drop(bcx.gctx.shell().note(&suggestion_message)); + } drop(bcx.gctx.shell().note(&format!( "this report can be shown with `cargo report \ future-incompatibilities --id {}`", diff --git a/src/cargo/core/compiler/job_queue/mod.rs b/src/cargo/core/compiler/job_queue/mod.rs index b04e6a42bae..1b63cdabca6 100644 --- a/src/cargo/core/compiler/job_queue/mod.rs +++ b/src/cargo/core/compiler/job_queue/mod.rs @@ -700,9 +700,15 @@ impl<'gctx> DrainState<'gctx> { } } Message::FutureIncompatReport(id, items) => { - let package_id = self.active[&id].pkg.package_id(); + let unit = &self.active[&id]; + let package_id = unit.pkg.package_id(); + let is_local = unit.is_local(); self.per_package_future_incompat_reports - .push(FutureIncompatReportPackage { package_id, items }); + .push(FutureIncompatReportPackage { + package_id, + is_local, + items, + }); } Message::Token(acquired_token) => { let token = acquired_token.context("failed to acquire jobserver token")?; diff --git a/tests/testsuite/future_incompat_report.rs b/tests/testsuite/future_incompat_report.rs index bb4e6dbecec..6e6f8c7ca53 100644 --- a/tests/testsuite/future_incompat_report.rs +++ b/tests/testsuite/future_incompat_report.rs @@ -15,14 +15,47 @@ use super::config::write_config_toml; // An arbitrary lint (unused_variables) that triggers a lint. // We use a special flag to force it to generate a report. -const FUTURE_EXAMPLE: &'static str = "fn main() { let x = 1; }"; +const FUTURE_EXAMPLE: &'static str = "pub fn foo() { let x = 1; }"; // Some text that will be displayed when the lint fires. const FUTURE_OUTPUT: &'static str = "[..]unused variable[..]"; -fn simple_project() -> Project { +/// A project with a future-incompat error in the local package. +fn local_project() -> Project { project() .file("Cargo.toml", &basic_manifest("foo", "0.0.0")) - .file("src/main.rs", FUTURE_EXAMPLE) + .file("src/lib.rs", FUTURE_EXAMPLE) + .build() +} + +/// A project with a future-incompat error in a dependency. +fn dependency_project() -> Project { + Package::new("bar", "1.0.0") + .file( + "Cargo.toml", + r#" + [package] + name = "bar" + version = "1.0.0" + edition = "2015" + repository = "https://example.com/" + "#, + ) + .file("src/lib.rs", FUTURE_EXAMPLE) + .publish(); + project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "1.0.0" + edition = "2015" + + [dependencies] + bar = "1.0" + "#, + ) + .file("src/lib.rs", "") .build() } @@ -30,17 +63,144 @@ fn simple_project() -> Project { nightly, reason = "-Zfuture-incompat-test requires nightly (permanently)" )] -fn output_on_stable() { - let p = simple_project(); +fn incompat_in_local_crate() { + // A simple example where a local crate triggers a future-incompatibility warning. + let p = local_project(); p.cargo("check") .env("RUSTFLAGS", "-Zfuture-incompat-test") .with_stderr_data(str![[r#" +[CHECKING] foo v0.0.0 ([ROOT]/foo) +[WARNING] unused variable: `x` ... + +[WARNING] `foo` (lib) generated 1 warning +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s +[WARNING] the following packages contain code that will be rejected by a future version of Rust: foo v0.0.0 ([ROOT]/foo) +[NOTE] to see what the problems were, use the option `--future-incompat-report`, or run `cargo report future-incompatibilities --id 1` + +"#]]) + .run(); + + p.cargo("check --future-incompat-report") + .env("RUSTFLAGS", "-Zfuture-incompat-test") + .with_stderr_data(str![[r#" [WARNING] unused variable: `x` ... + +[WARNING] `foo` (lib) generated 1 warning +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s +[WARNING] the following packages contain code that will be rejected by a future version of Rust: foo v0.0.0 ([ROOT]/foo) +[NOTE] this report can be shown with `cargo report future-incompatibilities --id 1` + +"#]]) + .run(); + + p.cargo("report future-incompatibilities --id 1") + .with_stdout_data(str![[r#" +The following warnings were discovered during the build. These warnings are an +indication that the packages contain code that will become an error in a +future release of Rust. These warnings typically cover changes to close +soundness problems, unintended or undocumented behavior, or critical problems +that cannot be fixed in a backwards-compatible fashion, and are not expected +to be in wide use. + +Each warning should contain a link for more information on what the warning +means and how to resolve it. + + +The package `foo v0.0.0 ([ROOT]/foo)` currently triggers the following future incompatibility lints: +> [WARNING] unused variable: `x` +... + +"#]]) + .run(); +} + +#[cargo_test( + nightly, + reason = "-Zfuture-incompat-test requires nightly (permanently)" +)] +fn incompat_in_dependency() { + // A simple example where a remote dependency triggers a future-incompatibility warning. + let p = dependency_project(); + + p.cargo("check") + .env("RUSTFLAGS", "-Zfuture-incompat-test") + .with_stderr_data(str![[r#" +[UPDATING] `dummy-registry` index +[LOCKING] 1 package to latest compatible version +[DOWNLOADING] crates ... +[DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) +[CHECKING] bar v1.0.0 +[CHECKING] foo v1.0.0 ([ROOT]/foo) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s +[WARNING] the following packages contain code that will be rejected by a future version of Rust: bar v1.0.0 [NOTE] to see what the problems were, use the option `--future-incompat-report`, or run `cargo report future-incompatibilities --id 1` +"#]]) + .run(); + + p.cargo("check --future-incompat-report") + .env("RUSTFLAGS", "-Zfuture-incompat-test") + .with_stderr_data(str![[r#" +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s +[WARNING] the following packages contain code that will be rejected by a future version of Rust: bar v1.0.0 +[NOTE] +To solve this problem, you can try the following approaches: + +- If the issue is not solved by updating the dependencies, a fix has to be +implemented by those dependencies. You can help with that by notifying the +maintainers of this problem (e.g. by creating a bug report) or by proposing a +fix to the maintainers (e.g. by creating a pull request): + + - bar@1.0.0 + - Repository: https://example.com/ + - Detailed warning command: `cargo report future-incompatibilities --id 1 --package bar@1.0.0` + +- If waiting for an upstream fix is not an option, you can use the `[patch]` +section in `Cargo.toml` to use your own version of the dependency. For more +information, see: +https://doc.rust-lang.org/cargo/reference/overriding-dependencies.html#the-patch-section + +[NOTE] this report can be shown with `cargo report future-incompatibilities --id 1` + +"#]]) + .run(); + + p.cargo("report future-incompatibilities --id 1") + .with_stdout_data(str![[r#" +The following warnings were discovered during the build. These warnings are an +indication that the packages contain code that will become an error in a +future release of Rust. These warnings typically cover changes to close +soundness problems, unintended or undocumented behavior, or critical problems +that cannot be fixed in a backwards-compatible fashion, and are not expected +to be in wide use. + +Each warning should contain a link for more information on what the warning +means and how to resolve it. + + +To solve this problem, you can try the following approaches: + +- If the issue is not solved by updating the dependencies, a fix has to be +implemented by those dependencies. You can help with that by notifying the +maintainers of this problem (e.g. by creating a bug report) or by proposing a +fix to the maintainers (e.g. by creating a pull request): + + - bar@1.0.0 + - Repository: https://example.com/ + - Detailed warning command: `cargo report future-incompatibilities --id 1 --package bar@1.0.0` + +- If waiting for an upstream fix is not an option, you can use the `[patch]` +section in `Cargo.toml` to use your own version of the dependency. For more +information, see: +https://doc.rust-lang.org/cargo/reference/overriding-dependencies.html#the-patch-section + +The package `bar v1.0.0` currently triggers the following future incompatibility lints: +> [WARNING] unused variable: `x` +... + "#]]) .run(); } @@ -48,7 +208,7 @@ fn output_on_stable() { // This feature is stable, and should not be gated #[cargo_test] fn no_gate_future_incompat_report() { - let p = simple_project(); + let p = local_project(); p.cargo("check --future-incompat-report") .with_status(0) @@ -98,7 +258,7 @@ fn test_zero_future_incompat() { reason = "-Zfuture-incompat-test requires nightly (permanently)" )] fn test_single_crate() { - let p = simple_project(); + let p = local_project(); for command in &["build", "check", "rustc", "test"] { let check_has_future_compat = || { @@ -155,7 +315,7 @@ frequency = 'never' ... [WARNING] the following packages contain code that will be rejected by a future version of Rust: foo v0.0.0 ([ROOT]/foo) ... - - foo@0.0.0 +[NOTE] this report can be shown with `cargo report future-incompatibilities --id [..]` ... ") .run(); @@ -315,7 +475,7 @@ The package `second-dep v0.0.2` currently triggers the following future incompat reason = "-Zfuture-incompat-test requires nightly (permanently)" )] fn color() { - let p = simple_project(); + let p = local_project(); p.cargo("check") .env("RUSTFLAGS", "-Zfuture-incompat-test") @@ -337,7 +497,7 @@ fn color() { reason = "-Zfuture-incompat-test requires nightly (permanently)" )] fn bad_ids() { - let p = simple_project(); + let p = local_project(); p.cargo("report future-incompatibilities --id 1") .with_status(101) @@ -391,6 +551,7 @@ fn suggestions_for_updates() { [package] name = "foo" version = "0.1.0" + edition = "2015" [dependencies] with_updates = "1" @@ -429,25 +590,179 @@ fn suggestions_for_updates() { .masquerade_as_nightly_cargo(&["future-incompat-test"]) .env("RUSTFLAGS", "-Zfuture-incompat-test") .with_stderr_data(str![[r#" -... +[DOWNLOADING] crates ... +[DOWNLOADED] without_updates v1.0.0 (registry `dummy-registry`) +[DOWNLOADED] with_updates v1.0.0 (registry `dummy-registry`) +[DOWNLOADED] big_update v1.0.0 (registry `dummy-registry`) +[CHECKING] with_updates v1.0.0 +[CHECKING] big_update v1.0.0 +[CHECKING] without_updates v1.0.0 +[CHECKING] foo v0.1.0 ([ROOT]/foo) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s +[WARNING] the following packages contain code that will be rejected by a future version of Rust: big_update v1.0.0, with_updates v1.0.0, without_updates v1.0.0 +[NOTE] +To solve this problem, you can try the following approaches: + + - Some affected dependencies have newer versions available. You may want to consider updating them to a newer version to see if the issue has been fixed. big_update v1.0.0 has the following newer versions available: 2.0.0 with_updates v1.0.0 has the following newer versions available: 1.0.1, 1.0.2, 3.0.1 -... -"#]]) + + +- If the issue is not solved by updating the dependencies, a fix has to be +implemented by those dependencies. You can help with that by notifying the +maintainers of this problem (e.g. by creating a bug report) or by proposing a +fix to the maintainers (e.g. by creating a pull request): + + - big_update@1.0.0 + - Repository: + - Detailed warning command: `cargo report future-incompatibilities --id 1 --package big_update@1.0.0` + + - with_updates@1.0.0 + - Repository: + - Detailed warning command: `cargo report future-incompatibilities --id 1 --package with_updates@1.0.0` + + - without_updates@1.0.0 + - Repository: + - Detailed warning command: `cargo report future-incompatibilities --id 1 --package without_updates@1.0.0` + +- If waiting for an upstream fix is not an option, you can use the `[patch]` +section in `Cargo.toml` to use your own version of the dependency. For more +information, see: +https://doc.rust-lang.org/cargo/reference/overriding-dependencies.html#the-patch-section +[NOTE] this report can be shown with `cargo report future-incompatibilities --id 1` + +"#]].unordered()) .run(); p.cargo("report future-incompatibilities") .with_stdout_data(str![[r#" -... +The following warnings were discovered during the build. These warnings are an +indication that the packages contain code that will become an error in a +future release of Rust. These warnings typically cover changes to close +soundness problems, unintended or undocumented behavior, or critical problems +that cannot be fixed in a backwards-compatible fashion, and are not expected +to be in wide use. + +Each warning should contain a link for more information on what the warning +means and how to resolve it. + + +To solve this problem, you can try the following approaches: + + - Some affected dependencies have newer versions available. You may want to consider updating them to a newer version to see if the issue has been fixed. big_update v1.0.0 has the following newer versions available: 2.0.0 with_updates v1.0.0 has the following newer versions available: 1.0.1, 1.0.2, 3.0.1 + +- If the issue is not solved by updating the dependencies, a fix has to be +implemented by those dependencies. You can help with that by notifying the +maintainers of this problem (e.g. by creating a bug report) or by proposing a +fix to the maintainers (e.g. by creating a pull request): + + - big_update@1.0.0 + - Repository: + - Detailed warning command: `cargo report future-incompatibilities --id 1 --package big_update@1.0.0` + + - with_updates@1.0.0 + - Repository: + - Detailed warning command: `cargo report future-incompatibilities --id 1 --package with_updates@1.0.0` + + - without_updates@1.0.0 + - Repository: + - Detailed warning command: `cargo report future-incompatibilities --id 1 --package without_updates@1.0.0` + +- If waiting for an upstream fix is not an option, you can use the `[patch]` +section in `Cargo.toml` to use your own version of the dependency. For more +information, see: +https://doc.rust-lang.org/cargo/reference/overriding-dependencies.html#the-patch-section + +The package `big_update v1.0.0` currently triggers the following future incompatibility lints: +> [WARNING] unused variable: `x` +... + +The package `with_updates v1.0.0` currently triggers the following future incompatibility lints: +> [WARNING] unused variable: `x` +... + +The package `without_updates v1.0.0` currently triggers the following future incompatibility lints: +> [WARNING] unused variable: `x` ... + +"#]]) + .run(); +} + +#[cargo_test( + nightly, + reason = "-Zfuture-incompat-test requires nightly (permanently)" +)] +fn correct_report_id_when_cached() { + // Checks for a bug where the `--id` value was off-by-one when the report + // is already cached. + let p = dependency_project(); + + p.cargo("check --future-incompat-report") + .env("RUSTFLAGS", "-Zfuture-incompat-test") + .with_stderr_data(str![[r#" +[UPDATING] `dummy-registry` index +[LOCKING] 1 package to latest compatible version +[DOWNLOADING] crates ... +[DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) +[CHECKING] bar v1.0.0 +[CHECKING] foo v1.0.0 ([ROOT]/foo) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s +[WARNING] the following packages contain code that will be rejected by a future version of Rust: bar v1.0.0 +[NOTE] +To solve this problem, you can try the following approaches: + +- If the issue is not solved by updating the dependencies, a fix has to be +implemented by those dependencies. You can help with that by notifying the +maintainers of this problem (e.g. by creating a bug report) or by proposing a +fix to the maintainers (e.g. by creating a pull request): + + - bar@1.0.0 + - Repository: https://example.com/ + - Detailed warning command: `cargo report future-incompatibilities --id 1 --package bar@1.0.0` + +- If waiting for an upstream fix is not an option, you can use the `[patch]` +section in `Cargo.toml` to use your own version of the dependency. For more +information, see: +https://doc.rust-lang.org/cargo/reference/overriding-dependencies.html#the-patch-section + +[NOTE] this report can be shown with `cargo report future-incompatibilities --id 1` + +"#]]) + .run(); + + p.cargo("check --future-incompat-report") + .env("RUSTFLAGS", "-Zfuture-incompat-test") + .with_stderr_data(str![[r#" +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s +[WARNING] the following packages contain code that will be rejected by a future version of Rust: bar v1.0.0 +[NOTE] +To solve this problem, you can try the following approaches: + +- If the issue is not solved by updating the dependencies, a fix has to be +implemented by those dependencies. You can help with that by notifying the +maintainers of this problem (e.g. by creating a bug report) or by proposing a +fix to the maintainers (e.g. by creating a pull request): + + - bar@1.0.0 + - Repository: https://example.com/ + - Detailed warning command: `cargo report future-incompatibilities --id 1 --package bar@1.0.0` + +- If waiting for an upstream fix is not an option, you can use the `[patch]` +section in `Cargo.toml` to use your own version of the dependency. For more +information, see: +https://doc.rust-lang.org/cargo/reference/overriding-dependencies.html#the-patch-section + +[NOTE] this report can be shown with `cargo report future-incompatibilities --id 1` + "#]]) .run(); }