about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2022-02-06 10:43:50 +0100
committerGitHub <noreply@github.com>2022-02-06 10:43:50 +0100
commit9f4559c3452239205015a02f2695ae1ec7d5c0f2 (patch)
tree69750cace21cee68a12bdf7abad08ae4c01ca6a5
parente069a711084b5617aecda7a5c8e88406ca12ed65 (diff)
parent1911eb8b6180f513a666372baf6e56f78b82dcd8 (diff)
downloadrust-9f4559c3452239205015a02f2695ae1ec7d5c0f2.tar.gz
rust-9f4559c3452239205015a02f2695ae1ec7d5c0f2.zip
Rollup merge of #90998 - jhpratt:require-const-stability, r=oli-obk
Require const stability attribute on all stable functions that are `const`

This PR requires all stable functions (of all kinds) that are `const fn` to have a `#[rustc_const_stable]` or `#[rustc_const_unstable]` attribute. Stability was previously implied if omitted; a follow-up PR is planned to change the fallback to be unstable.
-rw-r--r--compiler/rustc_passes/src/stability.rs36
-rw-r--r--library/core/src/array/mod.rs1
-rw-r--r--library/core/src/cell.rs1
-rw-r--r--library/core/src/num/int_macros.rs1
-rw-r--r--library/core/src/num/nonzero.rs1
-rw-r--r--library/core/src/num/uint_macros.rs1
-rw-r--r--src/test/ui/stability-attribute/missing-const-stability.rs26
-rw-r--r--src/test/ui/stability-attribute/missing-const-stability.stderr10
8 files changed, 51 insertions, 26 deletions
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 3521b6fc169..136059677c5 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/library/core/src/array/mod.rs b/library/core/src/array/mod.rs
index 121aa634deb..ee79021ed53 100644
--- a/library/core/src/array/mod.rs
+++ b/library/core/src/array/mod.rs
@@ -512,6 +512,7 @@ impl<T, const N: usize> [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 5fd60b75928..feb94555658 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -1959,6 +1959,7 @@ impl<T: ?Sized> UnsafeCell<T> {
     /// ```
     #[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<T>` 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 9949ecf0d36..c5e8408d904 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 e21ae489179..1ebd1c58f2b 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 555e121f9d0..052db4e3b3d 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 7d499c611a4..57e64737d0f 100644
--- a/src/test/ui/stability-attribute/missing-const-stability.rs
+++ b/src/test/ui/stability-attribute/missing-const-stability.rs
@@ -1,12 +1,26 @@
 #![feature(staged_api)]
+#![feature(const_trait_impl)]
+#![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 because function is unstable
 
-#[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 because function is unstable
+}
+
+// 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 450a5303fd8..7eba99a477a 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]`
+error: function has missing const stability attribute
   --> $DIR/missing-const-stability.rs:6: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:15:5
+   |
+LL |     pub const fn foo() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors