diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index be76d6cef2b88..c11c38500345a 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -739,6 +739,12 @@ passes_unrecognized_repr_hint = unrecognized representation hint .help = valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` +passes_unstable_attr_for_already_stable_feature = + can't mark as unstable using an already stable feature + .label = this feature is already stable + .item = the stability attribute annotates this item + .help = consider removing the attribute + passes_unused = unused attribute .suggestion = remove this attribute diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 4f00c90fa3b0f..f9186d3089ab3 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1480,6 +1480,17 @@ pub(crate) struct CannotStabilizeDeprecated { pub item_sp: Span, } +#[derive(Diagnostic)] +#[diag(passes_unstable_attr_for_already_stable_feature)] +pub(crate) struct UnstableAttrForAlreadyStableFeature { + #[primary_span] + #[label] + #[help] + pub span: Span, + #[label(passes_item)] + pub item_sp: Span, +} + #[derive(Diagnostic)] #[diag(passes_missing_stability_attr)] pub(crate) struct MissingStabilityAttr<'a> { diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 46b67e930d5e9..751c87a9fe519 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -10,6 +10,7 @@ use rustc_attr::{ }; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet}; +use rustc_feature::ACCEPTED_FEATURES; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalModDefId}; @@ -246,12 +247,27 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } + if let Stability { level: Unstable { .. }, feature } = stab { + if ACCEPTED_FEATURES.iter().find(|f| f.name == feature).is_some() { + self.tcx + .dcx() + .emit_err(errors::UnstableAttrForAlreadyStableFeature { span, item_sp }); + } + } if let Stability { level: Unstable { implied_by: Some(implied_by), .. }, feature } = stab { self.index.implications.insert(implied_by, feature); } + if let Some(ConstStability { level: Unstable { .. }, feature, .. }) = const_stab { + if ACCEPTED_FEATURES.iter().find(|f| f.name == feature).is_some() { + self.tcx.dcx().emit_err(errors::UnstableAttrForAlreadyStableFeature { + span: const_span.unwrap(), // If const_stab contains Some(..), same is true for const_span + item_sp, + }); + } + } if let Some(ConstStability { level: Unstable { implied_by: Some(implied_by), .. }, feature, diff --git a/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.rs b/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.rs new file mode 100644 index 0000000000000..9e697aaa0dcef --- /dev/null +++ b/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.rs @@ -0,0 +1,10 @@ +//! Ensure #[unstable] doesn't accept already stable features + +#![feature(staged_api)] +#![stable(feature = "rust_test", since = "1.0.0")] + +#[unstable(feature = "arbitrary_enum_discriminant", issue = "42")] //~ ERROR can't mark as unstable using an already stable feature +#[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")] //~ ERROR can't mark as unstable using an already stable feature +const fn my_fun() {} + +fn main() {} diff --git a/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr b/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr new file mode 100644 index 0000000000000..319056a9c8898 --- /dev/null +++ b/tests/ui/feature-gates/unstable-attribute-rejects-already-stable-features.stderr @@ -0,0 +1,31 @@ +error: can't mark as unstable using an already stable feature + --> $DIR/unstable-attribute-rejects-already-stable-features.rs:6:1 + | +LL | #[unstable(feature = "arbitrary_enum_discriminant", issue = "42")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this feature is already stable +LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")] +LL | const fn my_fun() {} + | -------------------- the stability attribute annotates this item + | +help: consider removing the attribute + --> $DIR/unstable-attribute-rejects-already-stable-features.rs:6:1 + | +LL | #[unstable(feature = "arbitrary_enum_discriminant", issue = "42")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: can't mark as unstable using an already stable feature + --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1 + | +LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this feature is already stable +LL | const fn my_fun() {} + | -------------------- the stability attribute annotates this item + | +help: consider removing the attribute + --> $DIR/unstable-attribute-rejects-already-stable-features.rs:7:1 + | +LL | #[rustc_const_unstable(feature = "arbitrary_enum_discriminant", issue = "42")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors +