about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_attr/src/builtin.rs28
-rw-r--r--compiler/rustc_middle/src/middle/stability.rs11
-rw-r--r--compiler/rustc_passes/src/stability.rs1
-rw-r--r--compiler/rustc_resolve/src/macros.rs11
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--src/test/ui/stability-attribute/auxiliary/stability-attribute-implies.rs8
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-implies-no-feature.rs13
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-implies-no-feature.stderr21
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-implies-using-stable.rs15
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-implies-using-stable.stderr14
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-implies-using-unstable.rs17
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-implies-using-unstable.stderr14
12 files changed, 150 insertions, 4 deletions
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index 16e56c6d851..64a6f91f022 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -142,6 +142,26 @@ pub enum StabilityLevel {
         /// Relevant `rust-lang/rust` issue.
         issue: Option<NonZeroU32>,
         is_soft: bool,
+        /// 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() {}
+        /// ```
+        implied_by: Option<Symbol>,
     },
     /// `#[stable]`
     Stable {
@@ -256,6 +276,7 @@ where
                     let mut issue = None;
                     let mut issue_num = None;
                     let mut is_soft = false;
+                    let mut implied_by = None;
                     for meta in metas {
                         let Some(mi) = meta.meta_item() else {
                             handle_errors(
@@ -321,6 +342,11 @@ where
                                 }
                                 is_soft = true;
                             }
+                            sym::implied_by => {
+                                if !get(mi, &mut implied_by) {
+                                    continue 'outer;
+                                }
+                            }
                             _ => {
                                 handle_errors(
                                     &sess.parse_sess,
@@ -345,7 +371,7 @@ where
                                 );
                                 continue;
                             }
-                            let level = Unstable { reason, issue: issue_num, is_soft };
+                            let level = Unstable { reason, issue: issue_num, is_soft, implied_by };
                             if sym::unstable == meta_name {
                                 stab = Some((Stability { level, feature }, attr.span));
                             } else {
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index 96e068a3601..63f66be1507 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -423,7 +423,9 @@ impl<'tcx> TyCtxt<'tcx> {
 
         match stability {
             Some(Stability {
-                level: attr::Unstable { reason, issue, is_soft }, feature, ..
+                level: attr::Unstable { reason, issue, is_soft, implied_by },
+                feature,
+                ..
             }) => {
                 if span.allows_unstable(feature) {
                     debug!("stability: skipping span={:?} since it is internal", span);
@@ -433,6 +435,13 @@ impl<'tcx> TyCtxt<'tcx> {
                     return EvalResult::Allow;
                 }
 
+                // If this item was previously part of a now-stabilized feature which is still
+                // active (i.e. the user hasn't removed the attribute for the stabilized feature
+                // yet) then allow use of this item.
+                if let Some(implied_by) = implied_by && self.features().active(implied_by) {
+                    return EvalResult::Allow;
+                }
+
                 // When we're compiling the compiler itself we may pull in
                 // crates from crates.io, but those crates may depend on other
                 // crates also pulled in from crates.io. We want to ideally be
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index da87f557a55..a15a42bd76f 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -637,6 +637,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
                     reason: Some(Symbol::intern(reason)),
                     issue: NonZeroU32::new(27812),
                     is_soft: false,
+                    implied_by: None,
                 },
                 feature: sym::rustc_private,
             };
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 54dd15270a1..2b5eb12a8a8 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -796,9 +796,16 @@ impl<'a> Resolver<'a> {
     ) {
         let span = path.span;
         if let Some(stability) = &ext.stability {
-            if let StabilityLevel::Unstable { reason, issue, is_soft } = stability.level {
+            if let StabilityLevel::Unstable { reason, issue, is_soft, implied_by } = stability.level
+            {
                 let feature = stability.feature;
-                if !self.active_features.contains(&feature) && !span.allows_unstable(feature) {
+
+                let is_allowed = |feature| {
+                    self.active_features.contains(&feature) || span.allows_unstable(feature)
+                };
+                let allowed_by_implication =
+                    implied_by.map(|feature| is_allowed(feature)).unwrap_or(false);
+                if !is_allowed(feature) && !allowed_by_implication {
                     let lint_buffer = &mut self.lint_buffer;
                     let soft_handler =
                         |lint, span, msg: &_| lint_buffer.buffer_lint(lint, node_id, span, msg);
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index ec1d2c39b80..2ac1ecfe87e 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -800,6 +800,7 @@ symbols! {
         impl_lint_pass,
         impl_macros,
         impl_trait_in_bindings,
+        implied_by,
         import,
         import_shadowing,
         imported_main,
diff --git a/src/test/ui/stability-attribute/auxiliary/stability-attribute-implies.rs b/src/test/ui/stability-attribute/auxiliary/stability-attribute-implies.rs
new file mode 100644
index 00000000000..468be1bc144
--- /dev/null
+++ b/src/test/ui/stability-attribute/auxiliary/stability-attribute-implies.rs
@@ -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() {}
diff --git a/src/test/ui/stability-attribute/stability-attribute-implies-no-feature.rs b/src/test/ui/stability-attribute/stability-attribute-implies-no-feature.rs
new file mode 100644
index 00000000000..947f9f73eff
--- /dev/null
+++ b/src/test/ui/stability-attribute/stability-attribute-implies-no-feature.rs
@@ -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'
+}
diff --git a/src/test/ui/stability-attribute/stability-attribute-implies-no-feature.stderr b/src/test/ui/stability-attribute/stability-attribute-implies-no-feature.stderr
new file mode 100644
index 00000000000..c2331f6766c
--- /dev/null
+++ b/src/test/ui/stability-attribute/stability-attribute-implies-no-feature.stderr
@@ -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`.
diff --git a/src/test/ui/stability-attribute/stability-attribute-implies-using-stable.rs b/src/test/ui/stability-attribute/stability-attribute-implies-using-stable.rs
new file mode 100644
index 00000000000..527639ec70b
--- /dev/null
+++ b/src/test/ui/stability-attribute/stability-attribute-implies-using-stable.rs
@@ -0,0 +1,15 @@
+// aux-build:stability-attribute-implies.rs
+#![deny(stable_features)]
+#![feature(foo)]
+//~^ ERROR the feature `foo` has been stable since 1.62.0 and no longer requires an attribute to enable
+
+// 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();
+}
diff --git a/src/test/ui/stability-attribute/stability-attribute-implies-using-stable.stderr b/src/test/ui/stability-attribute/stability-attribute-implies-using-stable.stderr
new file mode 100644
index 00000000000..c8767e85a68
--- /dev/null
+++ b/src/test/ui/stability-attribute/stability-attribute-implies-using-stable.stderr
@@ -0,0 +1,14 @@
+error: the feature `foo` has been stable since 1.62.0 and no longer requires an attribute to enable
+  --> $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)]
+   |         ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/stability-attribute/stability-attribute-implies-using-unstable.rs b/src/test/ui/stability-attribute/stability-attribute-implies-using-unstable.rs
new file mode 100644
index 00000000000..d6ad4d3510e
--- /dev/null
+++ b/src/test/ui/stability-attribute/stability-attribute-implies-using-unstable.rs
@@ -0,0 +1,17 @@
+// aux-build:stability-attribute-implies.rs
+#![deny(stable_features)]
+#![feature(foo)]
+//~^ ERROR the feature `foo` has been stable since 1.62.0 and no longer requires an attribute to enable
+
+// 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!
+}
diff --git a/src/test/ui/stability-attribute/stability-attribute-implies-using-unstable.stderr b/src/test/ui/stability-attribute/stability-attribute-implies-using-unstable.stderr
new file mode 100644
index 00000000000..35cbac6035c
--- /dev/null
+++ b/src/test/ui/stability-attribute/stability-attribute-implies-using-unstable.stderr
@@ -0,0 +1,14 @@
+error: the feature `foo` has been stable since 1.62.0 and no longer requires an attribute to enable
+  --> $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)]
+   |         ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+