diff --git a/text/0000-cargo-report-future-incompat.md b/text/0000-cargo-report-future-incompat.md new file mode 100644 index 00000000000..53131e5ce3b --- /dev/null +++ b/text/0000-cargo-report-future-incompat.md @@ -0,0 +1,771 @@ +- Feature Name: N/A +- Start Date: 2019-12-10 +- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) +- Rust Issue: N/A + +# Summary +[summary]: #summary + +Cargo should alert developers to upstream dependencies that trigger +future-incompatibility warnings. Cargo should list such dependencies +even when these warnings have been suppressed (e.g. via cap-lints or +`#[allow(..)]` attributes.) + +Cargo could additionally provide feedback for tactics a maintainer of +the downstream crate could use to address the problem (the details of +such tactics is not specified nor mandated by this RFC). + +# Motivation +[motivation]: #motivation + +From [rust-lang/rust#34596][]: + +> if you author a library that is widely used, but which you are not +> actively using at the moment, you might not notice that it will +> break in the future -- moreover, your users won't either, since +> cargo will cap lints when it builds your library as a dependency. + +[rust-lang/rust#34596]: https://github.com/rust-lang/rust/issues/34596 + +Today, cargo will cap lints when it builds libraries as dependencies. +This behavior includes future-incompatibility lints. + +As a running example, assume we have a crate `unwary` with an upstream +crate dependency `brash`, and `brash` has code that triggers a +future-incompatibility lint, in this case a borrow `&x.data.0` of a packed field +(see [rust-lang/rust#46043][], "safe packed borrows"). + +[rust-lang/rust#46043]: https://github.com/rust-lang/rust/issues/46043 + +If `brash` is a non-path dependency of `unwary`, then building +`unwary` will suppress the warning associated with `brash` in its +diagnostic output, because the build of `brash` will pass +`--cap-lints=allow` to its `rustc` invocation. This means that a +future version of Rust is going to fail to compile the `unwary` +project, with no warning to the developer of `unwary`. + +Example of today's behavior (where in this case, `brash` is non-path dependency of `unwary`): + +``` +crates % cd unwary +unwary % cargo build # no warning issued about problem in the `brash` dependency. + Compiling brash v0.1.0 + Compiling unwary v0.1.0 (/tmp/unwary) + Finished dev [unoptimized + debuginfo] target(s) in 0.30s +unwary % cd ../brash +brash % cargo build # (but a `brash` developer will see it when they build.) + Compiling brash v0.1.0 (/tmp/brash) +warning: borrow of packed field is unsafe and requires unsafe function or block (error E0133) + --> src/lib.rs:13:9 + | +13 | let y = &x.data.0; + | ^^^^^^^^^ + | + = note: `#[warn(safe_packed_borrows)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #46043 + = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior + Finished dev [unoptimized + debuginfo] target(s) in 0.30s +brash % +``` + +Cargo passes `--cap-lints=allow` on upstream dependencies for good +reason, as discussed in [Rust RFC 1193][] and the comment thread from +[rust-lang/rust#59658][]. +For cases like future-incompatibility lints, which +are more severe warnings for the long-term viability of a crate, we +need to provide some feedback to the `unwary` maintainer. + +But this feedback should not be *just* the raw diagnostic output for +`brash`! The developer of a crate like `unwary` typically cannot do +anything in the short term about warnings emitted by upstream crates, + + * (The `unwary` developer *can* file issues against `brash` or even + contribute code to fix `brash`, but that does not resolve the + immediate problem until a new version of `brash` is released by its + maintainer.) + +Therefore the diagnostics associated with building upstream +`brash` are usually just noise from the viewpoint of `unwary`'s +maintainer. + +[Rust RFC 1193]: https://github.com/rust-lang/rfcs/blob/master/text/1193-cap-lints.md + +[rust-lang/rfcs#1193]: https://github.com/rust-lang/rfcs/pull/1193 + +[rust-lang/rust#59658]: https://github.com/rust-lang/rust/issues/59658 + +[rust-lang/rust#27260]: https://github.com/rust-lang/rust/pull/27260 + +[rust-lang/cargo#1830]: https://github.com/rust-lang/cargo/pull/1830 + +Therefore, we want to continue passing `--cap-lints=allow` for +upstream dependencies. But we also want `rustc` to tell `cargo` (via +some channel) about when future-incompatibility lints are triggered, +and we want `cargo` to provide a succinct report of the triggers. + +This RFC suggests the provided feedback take the form of a summary at +the end of cargo's build of `unwary`, as illustrated in the explanation below. + +Furthermore, we want the feedback to provide guidance as to how the +`unwary` maintainer can address the issue. Here are some potential +forms this additional guidance could take. + + * cargo could respond to the future-incompatibilty signaling by querying + the local index to find out if a newer version of the upstream crate is + available. If a newer version is available, then it could + suggest to the user they might upgrade to it. + If such an upgrade could be done via `cargo update`, then the + output could obviously suggest that as well. + + (This is just a heuristic measure, as it would not attempt to + check ahead of time if the newer version actually resolves the + problem in question.) + + A further refinement on this idea would be to query + `crates.io` itself If cargo is not running in "offline mode". But + querying the index may well suffice in practice. + + * Cargo could suggest to the `unwary` maintainer that they file a bug + (or search for previously-filed bugs) in the source repository for + the upstream crate that is issuing the future-incompatibility + warning. (That is, the `brash` author might not be aware of the + issue; for example, if they last updated their crate before the + lint in question was deployed on the Rust compiler.) + + * `rustc` itself could embed, for each future-incompatibility lint, + how soon the Rust developers will turn the lint to a hard error. + This would give the `unwary` maintainer an idea of how much time + they have before they will be forced to address the issue (by + posting a PR upstream, or switching to a fork of `brash`, et + cetera). + + +# Guide-level explanation +[guide-level-explanation]: #guide-level-explanation + +After cargo finishes compiling a crate and its upstream dependencies, +it may include a final warning about *future incompatibilties*. + +A future incompatibility is a pattern of code that is scheduled to be +removed from the Rust language in some future release. Such code patterns +are usually instances of constructs that can exhibit undefined behavior +(i.e. they are unsound) or do not have a well-defined semantics, +but are nonetheless in widespread use and thus need a +grace period before they are removed. + +If any crate or any of its upstream dependencies has code that +triggers a future incompatibility warning, but the overall compilation +is otherwise without error, then cargo will report all instances of +crates with future incompatibilities at the end of the compilation. +When possible, this report includes the future date or release version +where we expect Rust to stop compiling the code in question. + +Example: + +``` +crates % cd unwary +unwary % cargo build + Compiling brash v0.1.0 + Compiling bold v0.1.0 + Compiling rash v0.1.0 + Compiling unwary v0.1.0 + Finished dev [unoptimized + debuginfo] target(s) in 0.30s + + warning: the crates brash, bold, and rash contain code that will be rejected by a future version of Rust. + note: the crate rash will stop compiling in Rust 1.50 (scheduled for February 2021). + note: to see what the problems were, invoke `cargo describe-future-incompatibilities` +unwary % +``` + +If the dependency graph for the current crate contains multiple versions of +a crate listed by the end report, then the end report should include which +version (or versions) of that crate are causing the lint to fire. + +Invoking the command `cargo describe-future-incompatibilities` will make cargo +query information cached from the previous build and print out a more informative +diagnostic message: + +``` +unary % cargo describe-future-incompatibilities +The `brash` crate currently triggers a future incompatibility warning with Rust, +with the following diagnostic: + +> warning: borrow of packed field is unsafe and requires unsafe function or block (error E0133) +> --> src/lib.rs:12:9 +> | +> 12 | let y = &x.data.0; // UB, also future-compatibility warning +> | ^^^^^^^^^ +> | +> = note: `#[warn(safe_packed_borrows)]` on by default +> = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +> = note: for more information, see issue #46043 +> = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior + + +The `bold` crate currently triggers a future incompatibility warning with Rust, +with the following diagnostic: + +> warning: private type `foo::m::S` in public interface (error E0446) +> --> src/lib.rs:5:5 +> | +> 5 | pub fn f() -> S { S } +> | ^^^^^^^^^^^^^^^^^^^^^ +> | +> = note: `#[warn(private_in_public)]` on by default +> = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +> = note: for more information, see issue #34537 + + +The `rash` crate currently triggers a future incompatibility warning with Rust, +with the following diagnostic: + +> error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions. +> --> src/lib.rs:4:8 +> | +> 4 | fn bar(x: T) { } +> | ^ +> | +> = note: `#[deny(invalid_type_param_default)]` on by default +> = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +> = note: for more information, see issue #36887 +``` + +This way, developers who want to understand the problem have a way to find out more, +without flooding everyone's diagnostics with information they cannot use with their +own local development. + + +Rebuilding `unwary` continues to emit the report even if the upstream +dependencies are not rebuilt. + +Example: + +``` +unwary % touch src/main.rs +unwary % cargo build + Compiling unwary v0.1.0 + Finished dev [unoptimized + debuginfo] target(s) in 0.30s + + warning: the crates brash, bold, and rash contain code that will be rejected by a future version of Rust. + note: the crate rash will stop compiling in Rust 1.50 (scheduled for February 2021). +unwary % + note: to see what the problems were, invoke `cargo describe-future-incompatibilities` +``` + +To keep the user experience consistent, we should probably emit the same warning at the end +even when the root crate is the sole trigger of incompatibility lints. + +``` +crates % cd brash +brash % cargo build + Compiling brash v0.1.0 (/tmp/brash) +warning: borrow of packed field is unsafe and requires unsafe function or block (error E0133) + --> src/lib.rs:13:9 + | +13 | let y = &x.data.0; + | ^^^^^^^^^ + | + = note: `#[warn(safe_packed_borrows)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #46043 + = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior + Finished dev [unoptimized + debuginfo] target(s) in 0.30s + + warning: the crate brash contains code that will be rejected by a future version of Rust. +brash % cargo build + Finished dev [unoptimized + debuginfo] target(s) in 0.00s + + warning: the crate brash contains code that will be rejected by a future version of Rust. + note: to see what the problems were, invoke `cargo describe-future-incompatibilities` +brash % +``` + +And as you might expect, if there are no future-incompatibilty warnings issused, then the output of `cargo` is unchanged from today. +Example: + +``` +crates % cd unwary +unwary % cargo build + Compiling brash v0.2.0 + Compiling bold2 v0.1.0 + Compiling unwary v0.2.0 + Finished dev [unoptimized + debuginfo] target(s) in 0.30s +unwary % +``` + +Here, the unwary (sic) crate has updated its version of `brash`, +switched to `bold2` (a fork of `bold`), and replaced its internal +usage of `rash` with some local code, thus completely eliminating all +current future-incompatibility lint triggers. + +# Reference-level explanation +[reference-level-explanation]: #reference-level-explanation + +As noted above, we want to continue to suppress normal lint checks for +upstream dependencies. Therefore, Cargo will continue to pass +`--cap-lints=allow` for non-path upstream dependencies. + +At the same time, we want to minimize disruption to existing users of Rust. + +Therefore, the behavior of flags that directly interact with lints, like +`-Dwarnings`, will remain unchanged by this RFC. + +For example, in our running example of `unwary`: + * running either `cargo rustc -- -Dwarnings` or `RUSTFLAGS=-Dwarnings cargo build` + will invoke `rustc` itself the same way, and each `rustc` invocation will emit + the same set of diagnostics that it does today for each of those cases. + * Thus, the warning lints in the downstream `brash` non-path dependency will + be capped, and the future-incompatiblity warnings associated with that `rustc` + invocation will be hidden. + * When `cargo` emits a future-incompatibility report at the end of the build, + and reports that `brash` contains code that will be rejected by + a future version of Rust, this report is *not* a lint, and does *not* interact + with `-Dwarnings`. + * In summary: getting a future-incompatibility report when you + have passed `-Dwarnings` to `rustc` will *not* fail the build. + +However, the Rust compiler's behavior *will* change slightly. Even when +`--cap-lints=allow` is turned on, we need Cargo to know when a +future-incompatibilty lint is triggered. + +The division of responsbiilties between Cargo and the Rust compiler +may be a little subtle: + +The responsibilities of the Rust compiler (`rustc`): + + * `rustc` must differentiate future-incompatibility lints (c.f. + [PR #59658: "Minimum Lint Levels"][rust-lang/rust#59658]) from + other lints that are expected to remain as mere warnings forever. + + * `rustc` will need to have some new mode of operation, which this + RFC will call the where it will check for instances of + future-incompatibility lints, *regardless* of whether + `--cap-lints=allow` is also set. This RFC calls this the + *future-incompatibility checking mode*. + + * In the future-incompatibility checking mode of invocation, + `rustc` will also need to check for such lints *regardless* of + whether the code appears in the scope of an `#[allow(..)]` + attribute for the lint. + + * In the future-incompatibility checking mode of invocation, + *emission* of the diagnostics themselves may still be silenced + as specified by `--cap-lints=allow` or `#[allow(..)]` attributes. + + * That is, those flags and annotations should be interpreted by + `rustc` as silencing the diagnostic report, but *not* as + silencing the feedback about there existing some instance of the + lint triggering somewhere in the crate's source code. + + * The future-incompatibility checking mode is meant as a way to + address the bulk of issue [rust-lang/rust#34596][]. + +The responsibilities of Cargo: + + * Cargo is responsible for invoking `rustc` in a way that enables + the future-incompatibility checking mode. This + mode of invocation occurs *regardless* of whether + `--cap-lints=allow` is also being passed when the crate is + compiled. + + * Cargo is responsible for capturing any output from the + future-incompatibility checking mode and summarizing it at the end + of the whole build. + + * Cargo is responsible for storing a record of any future-incompatibility + for a crate somewhere in the `target/` directory, so that it can + emit the same report without having to rebuild the crate on subsequent + rebuilds of the root crate. + + * Cargo is responsible for suggesting ways to address the problem to + the user. The specific tactics for constructing such suggestions + are not mandated by this RFC, but some ideas are presented as + [Future possibiilties][future-possibilities]. + +## Implmentation strategy: Leverage JSON error-format + +The cleanest way to implement the above division of responsbilities +without perturbing *non-cargo* uses of `rustc` is probably to make +the following change: + + * `rustc` should treat `--error-format=json` as signal that it should + emit a future-incompatibility summary report for the crate. + +It is relatively easy to extend the JSON output of `rustc` to include +a new record of any future-incompatibility lints that were triggered +when compiling a given crate. + + * However, this RFC does not *dictate* this choice of implementation + strategy. (Other options include using some environment variable to + opt-in to a change to `rustc`'s output, or having `rustc` emit + future-incompatibility metadata to the filesystem.) + +Some (but not all) future-incompatibility lints will have a concrete +schedule established for when they are meant to become hard errors. +(This RFC does not specify the details about how such schedules are +established or what constraints they will have to meet; it just posits +that they *will* be established by some means.) The metadata for every +future-incompatibility lint should include the anticipated version of +Rust, if known, where it will become a hard error. + + * This adds motivation for using JSON formatted diagnostics: JSON + records are more readily extensible, and thus can support adding + this sort of feedback in a robust fashion. + +Since `cargo` is expected to continue to emit the report even when the +upstream dependencies are not rebuilt, Cargo will store the +future-incompatibility status for each crate somewhere in the `target/` +directory on the file-system. +(This should be a trivial constraint today: Cargo on the nightly channel +is already locally caching warnings emitted while building upstream +path-dependencies.) + + +## Annoyance modulation + +Emitting a warning on all subsequent cargo invocations until the +problem is resolved may be overkill for some users. + +In particular, it may not be reasonable for someone to resolve the +flagged problem in the short term. + +In order to allow users to opt-out of being warned about future +incompatiblity issues on every build, this RFC proposes +extending the `.cargo/config` file with keys that allow +the user to fine-tune the frequency of how often cargo will +print the report. For example: + +``` +[future_incompatibility_report] +# This setting can be used to reduce the frequency with which Cargo will report +# future incompatibility issues. +# +# The possible values are: +# * "always" (default): always emit the report if any future incompatibility +# lint fires, +# * "never": never emit the report, +# * "post-cargo-update": emit the report the first time we encounter a given +# future incompatibility lint after the most recent +# `cargo update` run for a crate, +# * "daily": emit the report the first time any particular lint fires each day, +# * "weekly": emit the report the first time any particular lint fires +# each week (starting from Monday, following ISO 8601), +# * "lunar": emit the report the first time any particular lint fires every +# four weeks. (We recommend using this value in tandem with +# an IDE that presents the current phase of the moon in its UI.) +frequency = "always" + +# This allows a further fine-tuning for lints that have been given an +# explicit schedule for when they will be turned into hard errors. +# +# If false, such scheduled lints are treated the same as unscheduled ones. +# +# If true, such scheduled lints issue their report more frequently +# as time marches towards the release date when the warning becomes an error. +# +# Specifically, +# * 6 weeks before that release, the report is emitted at least once per week, +# * 2 weeks before that release, the report is emitted on every build. +# +# (Note that a consequence of the above definition, this value of this setting +# has no effect if the `future_incompat_report_frequency` is "always".) +telescoping_schedule = true +``` + +(This RFC does not actually prescribe the precise set of keys and +values laid out above. We trust the Cargo team to determine an +appropriate set of knobs to expose to the user.) + +## Policy issues + +We probably do not want to blindly convert all lints to +use this system. +The mechanism suggested here may not be appropriate for every single +lint currently categorized as `C-future-incompatility` on the Rust repo. +That decision is a policy matter for the relevant teams, +and the form of such policy is out of scope for this RFC. + +Whatever form that policy takes, it is worth noting: Users who encounter +upstream future-incompatibility issues may have neither free time nor external +development resources to draw upon. The rustc developers need to take some care +in deciding *when* a future-incompatibility lint should start being reported via +this mechanism. + + * If our primary goal is to minimize user frustration with our tools and + ecosystem, then future-incompatibility reporting for a given lint should be + turned only after much of the crate ecosystem have new fixed versions. In + other words, we should strive for a steady-state where the typical user + response to a future-incompatibility report is that user then runs + `cargo update`, or they ask for a (pre-existing) PR to be merged. + +# Drawbacks +[drawbacks]: #drawbacks + +The change as described requires revisions to both `rustc` and +`cargo`, which can be tricky to coordinate. + +This RFC suggests an approach where the changes are somewhat loosely +coupled: Use of `--error-format=json` will enable the +future-compatibility checking mode. This avoids the need to add a new +stable command line flag to `rustc`; but it also may be a confusing +change in compiler semantics for any non-cargo client of `rustc` that +is using `--error-format=json`. + +# Rationale and alternatives +[rationale-and-alternatives]: #rationale-and-alternatives + +## No change needed? + +Some claim that "our current approach" has been working, and therefore +no change is needed here. However, my counterargument is that the only +reason we haven't had to resolve this before is that compiler and +language teams have been forced to be very conservative in changing +existing future-incompatibility lints into hard errors, because it +takes a lot of effort to make such transitions, (in no small part +**because** of the issue described here). + +In the cases where the compiler and language teams have turned such +lints into hard errors, the teams spent signficant time evaluating +breakage via crater and then addressing such breakage. The changes +suggested here would hopefully encourage more Rust users *outside* of +the compiler and language teams to address future-compatibility +breakage. + +## Is there something simpler? + +One might well ask: Is this RFC overkill? Is there not a simpler way +to address this problem? + +The following is my attempt to enumerate the simple solutions that were obvious +to me. As we will see, these approaches would have serious drawbacks. + +### Can we do this in Cargo alone? + +With regards to implementation, we could avoid attempt making changes +to `rustc` itself, and isolate the implementation to `cargo` alone. +The main way I can imagine doing this is to stop passing +`--cap-lints=allow`, and then having Cargo capture all diagnostic +output from the compiler and post-processing it to determine which +lints are future-incompatible warnings. However, ths has a number of +problems: + + * It is fragile, since it relies on Cargo post-processing the compiler diagnostic output. + + * It is inefficient, since the compiler will now always run all the + lints checks for all dependencies of a crate but we only care about + a small subset of the lints. + + * It is insufficient, because it only handles instances of `--cap-lints`; it would + fail to catch instances where an upstream dependency is using an `#[allow(..)]` + attribute in the source to sidestep warnings. + + * If we addressed that insufficiency by unconditionally changing + `rustc` to always emit feedback about future-incompatibilities + regardless of `--cap-lints=allow` or `#[allow(..)]`, then that + would probably upset people who expect those flags/annotations to + keep the diagnostic output quiet. + + * (In other words, it would be an instance of + "the compiler is not listening to me!") + + * That is why this RFC proposes that `--cap-lints=allow` and + `#[allow(..)]` should continue to silence the diagnostic report + for lints listed by those flags and annotations, and restrict the + feedback solely to a final warning of the form "the crate brash + contains code that will be rejected by a future version of Rust." + +### Can we do this in Rust alone? + +PR [rust-lang/rust#59658][] "Minimum Lint Levels" implemented a +solution in the compiler alone, by tagging the future-incompatibility +lints as special cases that would not be silenced by `--cap-lints` nor +`#[allow(..)]`. The discussion on that PR described a number of +problems with this; in essence, people were concerned about getting +spammed by lints that the downstream developer couldn't actually do +anything about. + +The discussion on that PR concluded by saying that it could possibly +be reworked to reduce the amount of spam by reporting a single +instance of a lint for each dependency (rather than having a separate +diagnostic for each *expression* that triggered the lint within that +dependency). + + * The latter would indeed be an improvement on + [PR 59658][rust-lang/rust#59658], but it still would not be an ideal + user-experience. The change suggested by this RFC deliberately + treats occurrences of future-incompatibility lints as separate from + normal diagnostics: serious events worthy of being treated + specially by Cargo, to the extent that it might e.g. do an online query + to see if a newer version of the given crate exists. We want to + make the process of fixing these issues as easy as we can for the + developer, and doing that requires help from Cargo. + + * It is entirely possible that we will want to move forward with + minimum-lint levels, independently of this RFC. The machinery proposed + there is not in conflict with what I am proposing here; I am just saying that + it would not be sufficient for resolving the problem at hand. + +## Would extending cap-lints be preferable? + +One goal of the RFC as written was to try to minimize the impact on +the Rust ecosystem. Thus it does not change the behavior of the default +output error-format, and instead leverages `--error-format=json`. +But this might be too subtle an approach. + +One other way to still minimize impact would be to extend +the `--cap-lints` hierarchy so that it looks like this: + +``` +allow +warn-future-incompat +warn +deny-future-incompat +deny +``` + +Now, passing `--cap-lints=warn-future-incompat` would mean that we allow +(with no warning) all non-future-incompat lints, and warn on future-incompat ones. + +Likewise, `--cap-lints=deny-future-incompat` would mean that we warn +on all non-future-incompat lints, and error on future-incompat ones. + +Finally (and crucially), we would change the default for `cargo build` +to be `cap-lints=warn-future-incompat`. Then by default, developers +would be more directly informed about future incompatibilities in +their dependencies. + +I opted not to take this approach in the design proposed of this RFC +because I suspect it would suffer from the same problems exhibited by +["minimum lint levels"][rust-lang/rust#59658]: it would present a +bunch of diagnostics that developers cannot immediately resolve +locally. (However, it may still be a reasonable feature to add to +`rustc` and `cargo`!) + +# Prior art +[prior-art]: #prior-art + +None I know of, but I'm happy to be educated. + +(Has Python done anything here with the migration from Python 2 to +Python 3? I briefly did some web searches but failed to find much of +use.) + +# Unresolved questions +[unresolved-questions]: #unresolved-questions + +There are future-incompatibility warnings emitted by cargo itself, +such as discussed on [rust-lang/cargo#6313 (comment)][cargo 6313 comment]. I imagine it +shouldn't require much effort to incorporate support for such lints, but +I have not explicitly addressed nor seriously investigated this. + +[cargo 6313 comment]: https://github.com/rust-lang/cargo/issues/6313#issuecomment-505626509 + +## Implementation questions + +* Is using `--error-format=json` as the way to switch `rustc` into the future-incompatibility checking mode reasonable? + + * An variant on the strategy: + we could use the `--json CONFIG` option to `rustrc` as a way for + `cargo` to opt into the feature. + This way, clients already using `--error-format=json` + would not need to know abot this change. + +# Future possibilities +[future-possibilities]: #future-possibilities + +The main form of follow-up work I envisage for this RFC is what +feedback that Cargo gives regarding the issues. + +Cargo is responsible for suggesting to the user how they might address an +instance of a future-incompatbility lint. + +Some ideas for suggestions follow. + +## Query for newer/alternate versions of the crate + +When crates trigger future-incompatibility warnings, Cargo could look for newer versions of the dependency on crates.io. + +Example: + +``` +crates % cd unwary +unwary % cargo build + Compiling brash v0.1.0 + Compiling bold v0.1.0 + Compiling rash v0.1.0 + Compiling unwary v0.1.0 + Finished dev [unoptimized + debuginfo] target(s) in 0.30s + + warning: the crates brash, bold, and rash contain code that will be rejected by a future version of Rust. + note: the crate rash will stop compiling in Rust 1.50 (scheduled for February 2021). + note: newer versions of bold and rash are available; upgrading to them via `cargo update` may resolve their problems. +unwary % +``` + +This suggestion as written only covers upgrading to newer versions. +But with more help from crates.io itself, we could go even further +here: We could suggest potential *forks* of the upstream crate that +one might switch to using. This could be useful in dealing with +abandonware. + +## Suggest a bug report + +If no newer version of the triggering crate is available, Cargo could +emit a template for a bug report the user could file with the +upstream crate. + +Example: + +``` +crates % cd unwary +unwary % cargo build + Compiling brash v0.1.0 + Compiling unwary v0.1.0 + Finished dev [unoptimized + debuginfo] target(s) in 0.30s + + warning: the crate brash contains code that will be rejected by a future version of Rust. + note: the following gist contains a bug report you might consider filing with the maintainer of brash. + https://gist.github.com/pnkfelix/ae03d3ea95160fb71a797b15e05f8d49 +unwary % +``` + +In this example, the template is posted to a `gist` (The gist is using +my own github account here; to be honest I am not sure whether we +would be able to anonymously gist things from cargo in this manner, +but we should be able to find *some* pastebin service to use for this +purpose). + +For ease of reference, here is the text located at the gist url above: + +> This crate currently triggers a future incompatibility warning with Rust. +> +> In src/lib.rs:13:9, there is the following code: +> +> ```rust +> let y = &x.data.0; +> ``` +> +> This causes `rustc` to issue the following diagnostic, from https://github.com/rust-lang/rust/issues/46043 +> +> ``` +> warning: borrow of packed field is unsafe and requires unsafe function or block (error E0133) +> --> src/lib.rs:13:9 +> | +> 13 | let y = &x.data.0; +> | ^^^^^^^^^ +> | +> = note: `#[warn(safe_packed_borrows)]` on by default +> = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +> = note: for more information, see issue #46043 +> = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior +> ``` +> +> Since this construct is going to become a hard error in the future, we should eliminate occurrences of it. + +Further refinement of this idea: If we did start suggesting bug report +templates, then Cargo might also be able to *search* for issues with +descriptions that match the template on that crate's repostory, and +advise the user to inspect that bug report to see its current status, +rather than file a new bug with the upstream crate, which might be +otherwise annoying for those maintainers.