From 41f84c258ad5fc12775e25aafe4d67e3304a5bda Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Wed, 17 Nov 2021 21:06:17 -0500 Subject: [PATCH 1/2] Require const stability on all stable const items This was supposed to be the case previously, but a missed method call meant that trait impls were not checked. --- compiler/rustc_passes/src/stability.rs | 36 +++++++++---------- .../missing-const-stability.rs | 24 +++++++++---- .../missing-const-stability.stderr | 12 +++++-- 3 files changed, 45 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 3521b6fc1696c..136059677c5ae 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -577,17 +577,21 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { } fn check_missing_const_stability(&self, def_id: LocalDefId, span: Span) { - let stab_map = self.tcx.stability(); - let stab = stab_map.local_stability(def_id); - if stab.map_or(false, |stab| stab.level.is_stable()) { - let const_stab = stab_map.local_const_stability(def_id); - if const_stab.is_none() { - self.tcx.sess.span_err( - span, - "`#[stable]` const functions must also be either \ - `#[rustc_const_stable]` or `#[rustc_const_unstable]`", - ); - } + if !self.tcx.features().staged_api { + return; + } + + let is_const = self.tcx.is_const_fn(def_id.to_def_id()); + let is_stable = self + .tcx + .lookup_stability(def_id) + .map_or(false, |stability| stability.level.is_stable()); + let missing_const_stability_attribute = self.tcx.lookup_const_stability(def_id).is_none(); + let is_reachable = self.access_levels.is_reachable(def_id); + + if is_const && is_stable && missing_const_stability_attribute && is_reachable { + let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id()); + self.tcx.sess.span_err(span, &format!("{descr} has missing const stability attribute")); } } } @@ -612,13 +616,8 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { self.check_missing_stability(i.def_id, i.span); } - // Ensure `const fn` that are `stable` have one of `rustc_const_unstable` or - // `rustc_const_stable`. - if self.tcx.features().staged_api - && matches!(&i.kind, hir::ItemKind::Fn(sig, ..) if sig.header.is_const()) - { - self.check_missing_const_stability(i.def_id, i.span); - } + // Ensure stable `const fn` have a const stability attribute. + self.check_missing_const_stability(i.def_id, i.span); intravisit::walk_item(self, i) } @@ -632,6 +631,7 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { let impl_def_id = self.tcx.hir().get_parent_item(ii.hir_id()); if self.tcx.impl_trait_ref(impl_def_id).is_none() { self.check_missing_stability(ii.def_id, ii.span); + self.check_missing_const_stability(ii.def_id, ii.span); } intravisit::walk_impl_item(self, ii); } diff --git a/src/test/ui/stability-attribute/missing-const-stability.rs b/src/test/ui/stability-attribute/missing-const-stability.rs index 7d499c611a43c..39af6e9e3b935 100644 --- a/src/test/ui/stability-attribute/missing-const-stability.rs +++ b/src/test/ui/stability-attribute/missing-const-stability.rs @@ -1,12 +1,24 @@ #![feature(staged_api)] +#![stable(feature = "stable", since = "1.0.0")] -#![stable(feature = "rust1", since = "1.0.0")] +#[stable(feature = "stable", since = "1.0.0")] +pub const fn foo() {} //~ ERROR function has missing const stability attribute -#[stable(feature = "foo", since = "1.0.0")] -pub const fn foo() {} -//~^ ERROR rustc_const_stable +#[unstable(feature = "unstable", issue = "none")] +pub const fn bar() {} // ok for now -#[unstable(feature = "bar", issue = "none")] -pub const fn bar() {} // ok +#[stable(feature = "stable", since = "1.0.0")] +pub struct Foo; +impl Foo { + #[stable(feature = "stable", since = "1.0.0")] + pub const fn foo() {} //~ ERROR associated function has missing const stability attribute + + #[unstable(feature = "unstable", issue = "none")] + pub const fn bar() {} // ok for now +} + +// FIXME When #![feature(const_trait_impl)] is stabilized, add tests for const +// trait impls. Right now, a "trait methods cannot be stable const fn" error is +// emitted, but that's not in the scope of this test. fn main() {} diff --git a/src/test/ui/stability-attribute/missing-const-stability.stderr b/src/test/ui/stability-attribute/missing-const-stability.stderr index 450a5303fd86f..ee98e7b0e3fb1 100644 --- a/src/test/ui/stability-attribute/missing-const-stability.stderr +++ b/src/test/ui/stability-attribute/missing-const-stability.stderr @@ -1,8 +1,14 @@ -error: `#[stable]` const functions must also be either `#[rustc_const_stable]` or `#[rustc_const_unstable]` - --> $DIR/missing-const-stability.rs:6:1 +error: function has missing const stability attribute + --> $DIR/missing-const-stability.rs:5:1 | LL | pub const fn foo() {} | ^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: associated function has missing const stability attribute + --> $DIR/missing-const-stability.rs:14:5 + | +LL | pub const fn foo() {} + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors From 1911eb8b6180f513a666372baf6e56f78b82dcd8 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Wed, 17 Nov 2021 21:08:16 -0500 Subject: [PATCH 2/2] Add missing const stability attributes --- library/core/src/array/mod.rs | 1 + library/core/src/cell.rs | 1 + library/core/src/num/int_macros.rs | 1 + library/core/src/num/nonzero.rs | 1 + library/core/src/num/uint_macros.rs | 1 + .../stability-attribute/missing-const-stability.rs | 12 +++++++----- .../missing-const-stability.stderr | 4 ++-- 7 files changed, 14 insertions(+), 7 deletions(-) diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 121aa634deb33..ee79021ed536e 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -512,6 +512,7 @@ impl [T; N] { /// Returns a slice containing the entire array. Equivalent to `&s[..]`. #[stable(feature = "array_as_slice", since = "1.57.0")] + #[rustc_const_stable(feature = "array_as_slice", since = "1.57.0")] pub const fn as_slice(&self) -> &[T] { self } diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 5fd60b759286a..feb9455565844 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -1959,6 +1959,7 @@ impl UnsafeCell { /// ``` #[inline(always)] #[stable(feature = "unsafe_cell_raw_get", since = "1.56.0")] + #[rustc_const_stable(feature = "unsafe_cell_raw_get", since = "1.56.0")] pub const fn raw_get(this: *const Self) -> *mut T { // We can just cast the pointer from `UnsafeCell` to `T` because of // #[repr(transparent)]. This exploits libstd's special status, there is diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 79436c8e8ede4..3164b0c5d3cc6 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -1064,6 +1064,7 @@ macro_rules! int_impl { /// /// ``` #[stable(feature = "saturating_div", since = "1.58.0")] + #[rustc_const_stable(feature = "saturating_div", since = "1.58.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index e21ae48917953..1ebd1c58f2b59 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -972,6 +972,7 @@ macro_rules! nonzero_unsigned_is_power_of_two { /// ``` #[must_use] #[stable(feature = "nonzero_is_power_of_two", since = "1.59.0")] + #[rustc_const_stable(feature = "nonzero_is_power_of_two", since = "1.59.0")] #[inline] pub const fn is_power_of_two(self) -> bool { // LLVM 11 normalizes `unchecked_sub(x, 1) & x == 0` to the implementation seen here. diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 0bb654977764d..c1a134e68cde7 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -1132,6 +1132,7 @@ macro_rules! uint_impl { /// /// ``` #[stable(feature = "saturating_div", since = "1.58.0")] + #[rustc_const_stable(feature = "saturating_div", since = "1.58.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] diff --git a/src/test/ui/stability-attribute/missing-const-stability.rs b/src/test/ui/stability-attribute/missing-const-stability.rs index 39af6e9e3b935..57e64737d0faa 100644 --- a/src/test/ui/stability-attribute/missing-const-stability.rs +++ b/src/test/ui/stability-attribute/missing-const-stability.rs @@ -1,11 +1,12 @@ #![feature(staged_api)] +#![feature(const_trait_impl)] #![stable(feature = "stable", since = "1.0.0")] #[stable(feature = "stable", since = "1.0.0")] pub const fn foo() {} //~ ERROR function has missing const stability attribute #[unstable(feature = "unstable", issue = "none")] -pub const fn bar() {} // ok for now +pub const fn bar() {} // ok because function is unstable #[stable(feature = "stable", since = "1.0.0")] pub struct Foo; @@ -14,11 +15,12 @@ impl Foo { pub const fn foo() {} //~ ERROR associated function has missing const stability attribute #[unstable(feature = "unstable", issue = "none")] - pub const fn bar() {} // ok for now + pub const fn bar() {} // ok because function is unstable } -// FIXME When #![feature(const_trait_impl)] is stabilized, add tests for const -// trait impls. Right now, a "trait methods cannot be stable const fn" error is -// emitted, but that's not in the scope of this test. +// FIXME Once #![feature(const_trait_impl)] is allowed to be stable, add a test +// for const trait impls. Right now, a "trait methods cannot be stable const fn" +// error is emitted. This occurs prior to the lint being tested here, such that +// the lint cannot currently be tested on this use case. fn main() {} diff --git a/src/test/ui/stability-attribute/missing-const-stability.stderr b/src/test/ui/stability-attribute/missing-const-stability.stderr index ee98e7b0e3fb1..7eba99a477abe 100644 --- a/src/test/ui/stability-attribute/missing-const-stability.stderr +++ b/src/test/ui/stability-attribute/missing-const-stability.stderr @@ -1,11 +1,11 @@ error: function has missing const stability attribute - --> $DIR/missing-const-stability.rs:5:1 + --> $DIR/missing-const-stability.rs:6:1 | LL | pub const fn foo() {} | ^^^^^^^^^^^^^^^^^^^^^ error: associated function has missing const stability attribute - --> $DIR/missing-const-stability.rs:14:5 + --> $DIR/missing-const-stability.rs:15:5 | LL | pub const fn foo() {} | ^^^^^^^^^^^^^^^^^^^^^