Rollup merge of #99212 - davidtwco:partial-stability-implies, r=michaelwoerister

introduce `implied_by` in `#[unstable]` attribute

Requested by the library team [on Zulip](https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/better.20support.20for.20partial.20stabilizations/near/285581519).

If part of a feature is stabilized and a new feature is added for the remaining parts, then the `implied_by` meta-item can be added to `#[unstable]` to indicate which now-stable feature was used previously.

```diagnostic
error: the feature `foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `foobar`
  --> $DIR/stability-attribute-implies-using-unstable.rs:3:12
   |
LL | #![feature(foo)]
   |            ^^^
   |
note: the lint level is defined here
  --> $DIR/stability-attribute-implies-using-stable.rs:2:9
   |
LL | #![deny(stable_features)]
   |         ^^^^^^^^^^^^^^^
help: if you are using features which are still unstable, change to using `foobar`
   |
LL | #![feature(foobar)]
   |            ~~~~~~
help: if you are using features which are now stable, remove this line
   |
LL - #![feature(foo)]
   |
```

When a `#![feature(..)]` attribute still exists for the now-stable attribute, then there this has two effects:

- There will not be an stability error for uses of items from the implied feature which are still unstable (until the `#![feature(..)]` is removed or updated to the new feature).
- There will be an improved diagnostic for the remaining use of the feature attribute for the now-stable feature.

```rust
        /// If part of a feature is stabilized and a new feature is added for the remaining parts,
        /// then the `implied_by` attribute is used to indicate which now-stable feature previously
        /// contained a item.
        ///
        /// ```pseudo-Rust
        /// #[unstable(feature = "foo", issue = "...")]
        /// fn foo() {}
        /// #[unstable(feature = "foo", issue = "...")]
        /// fn foobar() {}
        /// ```
        ///
        /// ...becomes...
        ///
        /// ```pseudo-Rust
        /// #[stable(feature = "foo", since = "1.XX.X")]
        /// fn foo() {}
        /// #[unstable(feature = "foobar", issue = "...", implied_by = "foo")]
        /// fn foobar() {}
        /// ```
```

In the Zulip discussion, this was envisioned as `implies` on `#[stable]` but I went with `implied_by` on `#[unstable]` because it means that only the unstable attribute needs to be changed in future, not the new stable attribute, which seems less error-prone. It also isn't particularly feasible for me to detect whether items from the implied feature are used and then only suggest updating _or_ removing the `#![feature(..)]` as appropriate, so I always do both.

There's some new information in the cross-crate metadata as a result of this change, that's a little unfortunate, but without requiring that the `#[unstable]` and `#[stable]` attributes both contain the implication information, it's necessary:

```rust
    /// This mapping is necessary unless both the `#[stable]` and `#[unstable]` attributes should
    /// specify their implications (both `implies` and `implied_by`). If only one of the two
    /// attributes do (as in the current implementation, `implied_by` in `#[unstable]`), then this
    /// mapping is necessary for diagnostics. When a "unnecessary feature attribute" error is
    /// reported, only the `#[stable]` attribute information is available, so the map is necessary
    /// to know that the feature implies another feature. If it were reversed, and the `#[stable]`
    /// attribute had an `implies` meta item, then a map would be necessary when avoiding a "use of
    /// unstable feature" error for a feature that was implied.
```

I also change some comments to documentation comments in the compiler, add a helper for going from a `Span` to a `Span` for the entire line, and fix a incorrect part of the pre-existing stability attribute diagnostics.

cc `@yaahc`
This commit is contained in:
Matthias Krüger 2022-07-20 18:58:14 +02:00 committed by GitHub
commit 857afc75e6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 357 additions and 62 deletions

View file

@ -0,0 +1,8 @@
#![feature(staged_api)]
#![stable(feature = "stability_attribute_implies", since = "1.0.0")]
#[stable(feature = "foo", since = "1.62.0")]
pub fn foo() {}
#[unstable(feature = "foobar", issue = "1", implied_by = "foo")]
pub fn foobar() {}

View file

@ -0,0 +1,10 @@
#![feature(staged_api)]
#![stable(feature = "stability_attribute_implies", since = "1.0.0")]
// Tests that `implied_by = "bar"` results in an error being emitted if `bar` does not exist.
#[unstable(feature = "foobar", issue = "1", implied_by = "bar")]
//~^ ERROR feature `bar` implying `foobar` does not exist
pub fn foobar() {}
fn main() {}

View file

@ -0,0 +1,8 @@
error: feature `bar` implying `foobar` does not exist
--> $DIR/stability-attribute-implies-missing.rs:6:1
|
LL | #[unstable(feature = "foobar", issue = "1", implied_by = "bar")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error

View file

@ -0,0 +1,13 @@
// aux-build:stability-attribute-implies.rs
// Tests that despite the `foobar` feature being implied by now-stable feature `foo`, if `foobar`
// isn't allowed in this crate then an error will be emitted.
extern crate stability_attribute_implies;
use stability_attribute_implies::{foo, foobar};
//~^ ERROR use of unstable library feature 'foobar'
fn main() {
foo(); // no error - stable
foobar(); //~ ERROR use of unstable library feature 'foobar'
}

View file

@ -0,0 +1,21 @@
error[E0658]: use of unstable library feature 'foobar'
--> $DIR/stability-attribute-implies-no-feature.rs:7:40
|
LL | use stability_attribute_implies::{foo, foobar};
| ^^^^^^
|
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
= help: add `#![feature(foobar)]` to the crate attributes to enable
error[E0658]: use of unstable library feature 'foobar'
--> $DIR/stability-attribute-implies-no-feature.rs:12:5
|
LL | foobar();
| ^^^^^^
|
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
= help: add `#![feature(foobar)]` to the crate attributes to enable
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0658`.

View file

@ -0,0 +1,15 @@
// aux-build:stability-attribute-implies.rs
#![deny(stable_features)]
#![feature(foo)]
//~^ ERROR the feature `foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `foobar`
// Tests that the use of `implied_by` in the `#[unstable]` attribute results in a diagnostic
// mentioning partial stabilization, and that given the implied unstable feature is unused (there
// is no `foobar` call), that the compiler suggests removing the flag.
extern crate stability_attribute_implies;
use stability_attribute_implies::foo;
fn main() {
foo();
}

View file

@ -0,0 +1,22 @@
error: the feature `foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `foobar`
--> $DIR/stability-attribute-implies-using-stable.rs:3:12
|
LL | #![feature(foo)]
| ^^^
|
note: the lint level is defined here
--> $DIR/stability-attribute-implies-using-stable.rs:2:9
|
LL | #![deny(stable_features)]
| ^^^^^^^^^^^^^^^
help: if you are using features which are still unstable, change to using `foobar`
|
LL | #![feature(foobar)]
| ~~~~~~
help: if you are using features which are now stable, remove this line
|
LL - #![feature(foo)]
|
error: aborting due to previous error

View file

@ -0,0 +1,17 @@
// aux-build:stability-attribute-implies.rs
#![deny(stable_features)]
#![feature(foo)]
//~^ ERROR the feature `foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `foobar`
// Tests that the use of `implied_by` in the `#[unstable]` attribute results in a diagnostic
// mentioning partial stabilization and that given the implied unstable feature is used (there is a
// `foobar` call), that the compiler suggests changing to that feature and doesn't error about its
// use.
extern crate stability_attribute_implies;
use stability_attribute_implies::{foo, foobar};
fn main() {
foo();
foobar(); // no error!
}

View file

@ -0,0 +1,22 @@
error: the feature `foo` has been partially stabilized since 1.62.0 and is succeeded by the feature `foobar`
--> $DIR/stability-attribute-implies-using-unstable.rs:3:12
|
LL | #![feature(foo)]
| ^^^
|
note: the lint level is defined here
--> $DIR/stability-attribute-implies-using-unstable.rs:2:9
|
LL | #![deny(stable_features)]
| ^^^^^^^^^^^^^^^
help: if you are using features which are still unstable, change to using `foobar`
|
LL | #![feature(foobar)]
| ~~~~~~
help: if you are using features which are now stable, remove this line
|
LL - #![feature(foo)]
|
error: aborting due to previous error

View file

@ -8,7 +8,7 @@ error[E0541]: unknown meta item 'sinse'
--> $DIR/stability-attribute-sanity-2.rs:10:25
|
LL | #[stable(feature = "a", sinse = "1.0.0")]
| ^^^^^^^^^^^^^^^ expected one of `since`, `note`
| ^^^^^^^^^^^^^^^ expected one of `feature`, `since`
error[E0545]: `issue` must be a non-zero numeric string or "none"
--> $DIR/stability-attribute-sanity-2.rs:13:27

View file

@ -14,7 +14,7 @@ error[E0541]: unknown meta item 'reason'
--> $DIR/stability-attribute-sanity.rs:8:42
|
LL | #[stable(feature = "a", since = "b", reason)]
| ^^^^^^ expected one of `since`, `note`
| ^^^^^^ expected one of `feature`, `since`
error[E0539]: incorrect meta item
--> $DIR/stability-attribute-sanity.rs:11:29