diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index e9dcc120200d0..bc92ead17c88f 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -358,3 +358,72 @@ impl<'tcx> LateLintPass<'tcx> for ExistingDocKeyword { } } } + +declare_tool_lint! { + pub rustc::INCOMPATIBLE_STABILITY, + Deny, + "check that an unstable item is not const-stable" +} + +declare_lint_pass!(IncompatibleStability => [INCOMPATIBLE_STABILITY]); + +impl LateLintPass<'_> for IncompatibleStability { + fn check_fn( + &mut self, + cx: &LateContext<'_>, + kind: rustc_hir::intravisit::FnKind<'_>, + _: &FnDecl<'_>, + _: &Body<'_>, + span: rustc_span::Span, + hir_id: HirId, + ) { + use rustc_attr::{ConstStability, Stability, StabilityLevel}; + + // Perform a cheap check up-front to avoid unnecessary querying. + if kind.constness() == rustc_hir::Constness::NotConst { + return; + } + + if !matches!( + cx.tcx.lookup_stability(hir_id.owner), + Some(Stability { level: StabilityLevel::Unstable { .. }, .. }) + ) { + return; + } + if !matches!( + cx.tcx.lookup_const_stability(hir_id.owner), + Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) + ) { + return; + } + + cx.struct_span_lint(INCOMPATIBLE_STABILITY, span, |lint| { + lint.build("functions cannot be const-stable if they are unstable").emit(); + }); + } + + fn check_foreign_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::ForeignItem<'_>) { + use rustc_attr::{ConstStability, Stability, StabilityLevel}; + + if !matches!(item.kind, rustc_hir::ForeignItemKind::Fn(..)) { + return; + } + + if !matches!( + cx.tcx.lookup_stability(item.def_id), + Some(Stability { level: StabilityLevel::Unstable { .. }, .. }) + ) { + return; + } + if !matches!( + cx.tcx.lookup_const_stability(item.def_id), + Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) + ) { + return; + } + + cx.struct_span_lint(INCOMPATIBLE_STABILITY, item.span, |lint| { + lint.build("functions cannot be const-stable if they are unstable").emit(); + }); + } +} diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index f83eaabdfefcd..618abd6c05bf0 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -492,6 +492,8 @@ fn register_internals(store: &mut LintStore) { store.register_late_pass(|| Box::new(ExistingDocKeyword)); store.register_lints(&TyTyKind::get_lints()); store.register_late_pass(|| Box::new(TyTyKind)); + store.register_lints(&IncompatibleStability::get_lints()); + store.register_late_pass(|| Box::new(IncompatibleStability)); store.register_group( false, "rustc::internal", @@ -504,6 +506,7 @@ fn register_internals(store: &mut LintStore) { LintId::of(TY_PASS_BY_REFERENCE), LintId::of(USAGE_OF_QUALIFIED_TY), LintId::of(EXISTING_DOC_KEYWORD), + LintId::of(INCOMPATIBLE_STABILITY), ], ); } diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 1aeb83931e5aa..19116b2313111 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -53,6 +53,8 @@ issue = "none" )] #![allow(missing_docs)] +// intrinsics are never stable but may need to be const-stable for other items +#![cfg_attr(not(bootstrap), allow(rustc::incompatible_stability))] use crate::marker::DiscriminantKind; use crate::mem; diff --git a/library/core/src/num/saturating.rs b/library/core/src/num/saturating.rs index ba81f3f9fd6a0..d9b14c82e96ba 100644 --- a/library/core/src/num/saturating.rs +++ b/library/core/src/num/saturating.rs @@ -628,7 +628,7 @@ macro_rules! saturating_int_impl { /// ``` #[inline] #[unstable(feature = "saturating_int_impl", issue = "87920")] - #[rustc_const_stable(feature = "const_reverse_bits", since = "1.37.0")] + #[rustc_const_unstable(feature = "saturating_int_impl", issue = "87920")] #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn reverse_bits(self) -> Self { diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 507ff516a8f28..66b12848bab2b 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -2208,7 +2208,7 @@ macro_rules! uint_impl { /// ``` #[unstable(feature = "wrapping_next_power_of_two", issue = "32463", reason = "needs decision on wrapping behaviour")] - #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] + #[rustc_const_unstable(feature = "wrapping_next_power_of_two", issue = "32463")] #[must_use = "this returns the result of the operation, \ without modifying the original"] pub const fn wrapping_next_power_of_two(self) -> Self { diff --git a/src/test/ui/lint/incompatible_stability.rs b/src/test/ui/lint/incompatible_stability.rs new file mode 100644 index 0000000000000..20587daaccf14 --- /dev/null +++ b/src/test/ui/lint/incompatible_stability.rs @@ -0,0 +1,24 @@ +// compile-flags: -Zunstable-options +#![stable(feature = "stable", since = "1.0.0")] +#![feature(staged_api, rustc_attrs, intrinsics)] + +#[unstable(feature = "unstable", issue = "none")] +#[rustc_const_stable(feature = "stable", since = "1.0.0")] +const fn foo() {} //~ ERROR functions cannot be const-stable if they are unstable + +mod bar { + #![unstable(feature = "unstable", issue = "none")] + + #[rustc_const_stable(feature = "stable", since = "1.0.0")] + const fn foo() {} //~ ERROR functions cannot be const-stable if they are unstable +} + +mod intrinsics { + #![unstable(feature = "unstable", issue = "none")] + extern "rust-intrinsic" { + #[rustc_const_stable(feature = "stable", since = "1.0.0")] + pub fn transmute(_: T) -> U; //~ ERROR functions cannot be const-stable if they are unstable + } +} + +fn main() {} diff --git a/src/test/ui/lint/incompatible_stability.stderr b/src/test/ui/lint/incompatible_stability.stderr new file mode 100644 index 0000000000000..cea0e7e43ccb0 --- /dev/null +++ b/src/test/ui/lint/incompatible_stability.stderr @@ -0,0 +1,22 @@ +error: functions cannot be const-stable if they are unstable + --> $DIR/incompatible_stability.rs:7:1 + | +LL | const fn foo() {} + | ^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(rustc::incompatible_stability)]` on by default + +error: functions cannot be const-stable if they are unstable + --> $DIR/incompatible_stability.rs:13:5 + | +LL | const fn foo() {} + | ^^^^^^^^^^^^^^^^^ + +error: functions cannot be const-stable if they are unstable + --> $DIR/incompatible_stability.rs:20:9 + | +LL | pub fn transmute(_: T) -> U; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors +