about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-12-14 10:21:32 +0000
committerbors <bors@rust-lang.org>2019-12-14 10:21:32 +0000
commitc8ea4ace9213ae045123fdfeb59d1ac887656d31 (patch)
tree2a7d207294b6f2c99d1ddbe193b1d5af8ee46a09
parent12307b3b08edee543a78fb9d4a837fbd6d6ac0fa (diff)
parent0b47ba7019adf06f6687a8c94040e63ae1ea4fba (diff)
downloadrust-c8ea4ace9213ae045123fdfeb59d1ac887656d31.tar.gz
rust-c8ea4ace9213ae045123fdfeb59d1ac887656d31.zip
Auto merge of #67136 - oli-obk:const_stability, r=Centril
Require stable/unstable annotations for the constness of all stable fns with a const modifier

r? @RalfJung @Centril

Every `#[stable]` const fn now needs either a `#[rustc_const_unstable]` attribute or a `#[rustc_const_stable]` attribute. You can't silently stabilize the constness of a function anymore.
-rw-r--r--src/liballoc/collections/linked_list.rs4
-rw-r--r--src/liballoc/lib.rs2
-rw-r--r--src/liballoc/string.rs4
-rw-r--r--src/liballoc/vec.rs4
-rw-r--r--src/libcore/alloc.rs1
-rw-r--r--src/libcore/any.rs9
-rw-r--r--src/libcore/cell.rs11
-rw-r--r--src/libcore/char/methods.rs4
-rw-r--r--src/libcore/convert/mod.rs1
-rw-r--r--src/libcore/intrinsics.rs6
-rw-r--r--src/libcore/iter/sources.rs1
-rw-r--r--src/libcore/lib.rs2
-rw-r--r--src/libcore/mem/manually_drop.rs8
-rw-r--r--src/libcore/mem/maybe_uninit.rs8
-rw-r--r--src/libcore/mem/mod.rs3
-rw-r--r--src/libcore/num/mod.rs342
-rw-r--r--src/libcore/num/wrapping.rs4
-rw-r--r--src/libcore/ops/range.rs9
-rw-r--r--src/libcore/ptr/mod.rs16
-rw-r--r--src/libcore/ptr/non_null.rs16
-rw-r--r--src/libcore/slice/mod.rs9
-rw-r--r--src/libcore/str/mod.rs7
-rw-r--r--src/libcore/sync/atomic.rs16
-rw-r--r--src/libcore/task/wake.rs2
-rw-r--r--src/libcore/time.rs12
-rw-r--r--src/librustc/middle/stability.rs29
-rw-r--r--src/librustc/query/mod.rs1
-rw-r--r--src/librustc/ty/constness.rs50
-rw-r--r--src/librustc/ty/context.rs17
-rw-r--r--src/librustc_feature/active.rs4
-rw-r--r--src/librustc_feature/builtin_attrs.rs8
-rw-r--r--src/librustc_metadata/rmeta/decoder.rs4
-rw-r--r--src/librustc_metadata/rmeta/decoder/cstore_impl.rs3
-rw-r--r--src/librustc_metadata/rmeta/encoder.rs11
-rw-r--r--src/librustc_metadata/rmeta/mod.rs1
-rw-r--r--src/libstd/ffi/c_str.rs4
-rw-r--r--src/libstd/lib.rs2
-rw-r--r--src/libstd/net/ip.rs4
-rw-r--r--src/libstd/sync/once.rs1
-rw-r--r--src/libsyntax/attr/builtin.rs125
-rw-r--r--src/libsyntax_expand/base.rs6
-rw-r--r--src/libsyntax_pos/symbol.rs1
-rw-r--r--src/test/rustdoc/const-display.rs6
-rw-r--r--src/test/ui/consts/auxiliary/promotable_const_fn_lib.rs2
-rw-r--r--src/test/ui/consts/const-eval/auxiliary/stability.rs4
-rw-r--r--src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.rs4
-rw-r--r--src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs2
-rw-r--r--src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr2
-rw-r--r--src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs1
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs8
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr8
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs8
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr8
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs7
-rw-r--r--src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr6
-rw-r--r--src/test/ui/consts/unstable-const-fn-in-libcore.rs2
-rw-r--r--src/test/ui/feature-gate/allow-features-empty.rs2
-rw-r--r--src/test/ui/feature-gate/allow-features-empty.stderr12
-rw-r--r--src/test/ui/feature-gate/allow-features.rs2
-rw-r--r--src/test/ui/feature-gate/allow-features.stderr10
-rw-r--r--src/test/ui/feature-gates/feature-gate-rustc_const_unstable.rs5
-rw-r--r--src/test/ui/feature-gates/feature-gate-rustc_const_unstable.stderr8
-rw-r--r--src/test/ui/invalid_const_promotion.rs1
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-sanity.rs7
-rw-r--r--src/test/ui/stability-attribute/stability-attribute-sanity.stderr10
-rw-r--r--src/tools/tidy/src/error_codes_check.rs1
66 files changed, 717 insertions, 181 deletions
diff --git a/src/liballoc/collections/linked_list.rs b/src/liballoc/collections/linked_list.rs
index 6ee22834a46..4a74a479e71 100644
--- a/src/liballoc/collections/linked_list.rs
+++ b/src/liballoc/collections/linked_list.rs
@@ -275,6 +275,10 @@ impl<T> LinkedList<T> {
     /// let list: LinkedList<u32> = LinkedList::new();
     /// ```
     #[inline]
+    #[cfg_attr(
+        not(bootstrap),
+        rustc_const_stable(feature = "const_linked_list_new", since = "1.32.0"),
+    )]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub const fn new() -> Self {
         LinkedList {
diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs
index ddfa6797a57..d828e374a7b 100644
--- a/src/liballoc/lib.rs
+++ b/src/liballoc/lib.rs
@@ -117,7 +117,7 @@
 #![feature(unsized_locals)]
 #![feature(allocator_internals)]
 #![cfg_attr(bootstrap, feature(on_unimplemented))]
-#![feature(rustc_const_unstable)]
+#![cfg_attr(bootstrap, feature(rustc_const_unstable))]
 #![feature(slice_partition_dedup)]
 #![feature(maybe_uninit_extra, maybe_uninit_slice)]
 #![feature(alloc_layout_extra)]
diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs
index f7dff4c21f7..bf9bbba4753 100644
--- a/src/liballoc/string.rs
+++ b/src/liballoc/string.rs
@@ -367,6 +367,10 @@ impl String {
     /// let s = String::new();
     /// ```
     #[inline]
+    #[cfg_attr(
+        not(bootstrap),
+        rustc_const_stable(feature = "const_string_new", since = "1.32.0"),
+    )]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub const fn new() -> String {
         String { vec: Vec::new() }
diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs
index 6e165ccb919..52b45b0b8fe 100644
--- a/src/liballoc/vec.rs
+++ b/src/liballoc/vec.rs
@@ -315,6 +315,10 @@ impl<T> Vec<T> {
     /// let mut vec: Vec<i32> = Vec::new();
     /// ```
     #[inline]
+    #[cfg_attr(
+        not(bootstrap),
+        rustc_const_stable(feature = "const_vec_new", since = "1.32.0"),
+    )]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub const fn new() -> Vec<T> {
         Vec {
diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs
index 5c24e3d8f5d..71517ffb006 100644
--- a/src/libcore/alloc.rs
+++ b/src/libcore/alloc.rs
@@ -100,6 +100,7 @@ impl Layout {
     /// This function is unsafe as it does not verify the preconditions from
     /// [`Layout::from_size_align`](#method.from_size_align).
     #[stable(feature = "alloc_layout", since = "1.28.0")]
+    #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "alloc_layout", since = "1.28.0"))]
     #[inline]
     pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {
         Layout { size_: size, align_: NonZeroUsize::new_unchecked(align) }
diff --git a/src/libcore/any.rs b/src/libcore/any.rs
index 466750fc7d2..b0e3021e0bf 100644
--- a/src/libcore/any.rs
+++ b/src/libcore/any.rs
@@ -423,7 +423,8 @@ impl TypeId {
     /// assert_eq!(is_string(&"cookie monster".to_string()), true);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature="const_type_id")]
+    #[cfg_attr(bootstrap, rustc_const_unstable(feature="const_type_id"))]
+    #[cfg_attr(not(bootstrap), rustc_const_unstable(feature="const_type_id", issue = "41875"))]
     pub const fn of<T: ?Sized + 'static>() -> TypeId {
         TypeId {
             #[cfg(bootstrap)]
@@ -461,7 +462,8 @@ impl TypeId {
 /// );
 /// ```
 #[stable(feature = "type_name", since = "1.38.0")]
-#[rustc_const_unstable(feature = "const_type_name")]
+#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_type_name"))]
+#[cfg_attr(not(bootstrap), rustc_const_unstable(feature = "const_type_name", issue = "63084"))]
 pub const fn type_name<T: ?Sized>() -> &'static str {
     intrinsics::type_name::<T>()
 }
@@ -499,7 +501,8 @@ pub const fn type_name<T: ?Sized>() -> &'static str {
 /// println!("{}", type_name_of_val(&y));
 /// ```
 #[unstable(feature = "type_name_of_val", issue = "66359")]
-#[rustc_const_unstable(feature = "const_type_name")]
+#[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_type_name"))]
+#[cfg_attr(not(bootstrap), rustc_const_unstable(feature = "const_type_name", issue = "63084"))]
 pub const fn type_name_of_val<T: ?Sized>(val: &T) -> &'static str {
     let _ = val;
     type_name::<T>()
diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs
index 03f32e72618..e4b4cd31c63 100644
--- a/src/libcore/cell.rs
+++ b/src/libcore/cell.rs
@@ -324,6 +324,7 @@ impl<T> Cell<T> {
     /// let c = Cell::new(5);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "const_cell_new", since = "1.32.0"))]
     #[inline]
     pub const fn new(value: T) -> Cell<T> {
         Cell {
@@ -469,6 +470,7 @@ impl<T: ?Sized> Cell<T> {
     /// ```
     #[inline]
     #[stable(feature = "cell_as_ptr", since = "1.12.0")]
+    #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "const_cell_as_ptr", since = "1.32.0"))]
     pub const fn as_ptr(&self) -> *mut T {
         self.value.get()
     }
@@ -649,6 +651,7 @@ impl<T> RefCell<T> {
     /// let c = RefCell::new(5);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "const_refcell_new", since = "1.32.0"))]
     #[inline]
     pub const fn new(value: T) -> RefCell<T> {
         RefCell {
@@ -1501,6 +1504,10 @@ impl<T> UnsafeCell<T> {
     /// let uc = UnsafeCell::new(5);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(
+        not(bootstrap),
+        rustc_const_stable(feature = "const_unsafe_cell_new", since = "1.32.0"),
+    )]
     #[inline]
     pub const fn new(value: T) -> UnsafeCell<T> {
         UnsafeCell { value }
@@ -1543,6 +1550,10 @@ impl<T: ?Sized> UnsafeCell<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(
+        not(bootstrap),
+        rustc_const_stable(feature = "const_unsafecell_get", since = "1.32.0"),
+    )]
     pub const fn get(&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/src/libcore/char/methods.rs b/src/libcore/char/methods.rs
index 5c63eebf595..5cfb9583a86 100644
--- a/src/libcore/char/methods.rs
+++ b/src/libcore/char/methods.rs
@@ -911,6 +911,10 @@ impl char {
     /// assert!(!non_ascii.is_ascii());
     /// ```
     #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+    #[cfg_attr(
+        not(bootstrap),
+        rustc_const_stable(feature = "const_ascii_methods_on_intrinsics", since = "1.32.0"),
+    )]
     #[inline]
     pub const fn is_ascii(&self) -> bool {
         *self as u32 <= 0x7F
diff --git a/src/libcore/convert/mod.rs b/src/libcore/convert/mod.rs
index b7db3e4197d..cdd994d5fc7 100644
--- a/src/libcore/convert/mod.rs
+++ b/src/libcore/convert/mod.rs
@@ -99,6 +99,7 @@ pub use num::FloatToInt;
 /// assert_eq!(vec![1, 3], filtered);
 /// ```
 #[stable(feature = "convert_id", since = "1.33.0")]
+#[cfg_attr(not(bootstrap), rustc_const_stable(feature = "const_identity", since = "1.33.0"))]
 #[inline]
 pub const fn identity<T>(x: T) -> T {
     x
diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index 18aae59573d..1f72b7ab090 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -939,7 +939,11 @@ extern "rust-intrinsic" {
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[rustc_const_unstable(feature = "const_transmute")]
+    #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_transmute"))]
+    #[cfg_attr(
+        not(bootstrap),
+        rustc_const_unstable(feature = "const_transmute", issue = "53605"),
+    )]
     pub fn transmute<T, U>(e: T) -> U;
 
     /// Returns `true` if the actual type given as `T` requires drop
diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs
index ffac7d4e995..127b778e62e 100644
--- a/src/libcore/iter/sources.rs
+++ b/src/libcore/iter/sources.rs
@@ -281,6 +281,7 @@ impl<T> Default for Empty<T> {
 /// assert_eq!(None, nope.next());
 /// ```
 #[stable(feature = "iter_empty", since = "1.2.0")]
+#[cfg_attr(not(bootstrap), rustc_const_stable(feature = "const_iter_empty", since = "1.32.0"))]
 pub const fn empty<T>() -> Empty<T> {
     Empty(marker::PhantomData)
 }
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index 8a514f1e78e..146d582eb7a 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -96,7 +96,7 @@
 #![feature(prelude_import)]
 #![feature(repr_simd, platform_intrinsics)]
 #![feature(rustc_attrs)]
-#![feature(rustc_const_unstable)]
+#![cfg_attr(bootstrap, feature(rustc_const_unstable))]
 #![feature(simd_ffi)]
 #![feature(specialization)]
 #![feature(staged_api)]
diff --git a/src/libcore/mem/manually_drop.rs b/src/libcore/mem/manually_drop.rs
index 34fc0618ea2..6463668a03e 100644
--- a/src/libcore/mem/manually_drop.rs
+++ b/src/libcore/mem/manually_drop.rs
@@ -63,6 +63,10 @@ impl<T> ManuallyDrop<T> {
     /// ManuallyDrop::new(Box::new(()));
     /// ```
     #[stable(feature = "manually_drop", since = "1.20.0")]
+    #[cfg_attr(
+        not(bootstrap),
+        rustc_const_stable(feature = "const_manually_drop", since = "1.36.0"),
+    )]
     #[inline(always)]
     pub const fn new(value: T) -> ManuallyDrop<T> {
         ManuallyDrop { value }
@@ -80,6 +84,10 @@ impl<T> ManuallyDrop<T> {
     /// let _: Box<()> = ManuallyDrop::into_inner(x); // This drops the `Box`.
     /// ```
     #[stable(feature = "manually_drop", since = "1.20.0")]
+    #[cfg_attr(
+        not(bootstrap),
+        rustc_const_stable(feature = "const_manually_drop", since = "1.36.0"),
+    )]
     #[inline(always)]
     pub const fn into_inner(slot: ManuallyDrop<T>) -> T {
         slot.value
diff --git a/src/libcore/mem/maybe_uninit.rs b/src/libcore/mem/maybe_uninit.rs
index 6661df2ae0d..670a194e2d6 100644
--- a/src/libcore/mem/maybe_uninit.rs
+++ b/src/libcore/mem/maybe_uninit.rs
@@ -250,6 +250,10 @@ impl<T> MaybeUninit<T> {
     ///
     /// [`assume_init`]: #method.assume_init
     #[stable(feature = "maybe_uninit", since = "1.36.0")]
+    #[cfg_attr(
+        not(bootstrap),
+        rustc_const_stable(feature = "const_maybe_uninit", since = "1.36.0"),
+    )]
     #[inline(always)]
     pub const fn new(val: T) -> MaybeUninit<T> {
         MaybeUninit { value: ManuallyDrop::new(val) }
@@ -264,6 +268,10 @@ impl<T> MaybeUninit<T> {
     ///
     /// [type]: union.MaybeUninit.html
     #[stable(feature = "maybe_uninit", since = "1.36.0")]
+    #[cfg_attr(
+        not(bootstrap),
+        rustc_const_stable(feature = "const_maybe_uninit", since = "1.36.0"),
+    )]
     #[inline(always)]
     #[cfg_attr(all(not(bootstrap)), rustc_diagnostic_item = "maybe_uninit_uninit")]
     pub const fn uninit() -> MaybeUninit<T> {
diff --git a/src/libcore/mem/mod.rs b/src/libcore/mem/mod.rs
index ec926aa6c23..00b32ad0b73 100644
--- a/src/libcore/mem/mod.rs
+++ b/src/libcore/mem/mod.rs
@@ -271,6 +271,7 @@ pub fn forget_unsized<T: ?Sized>(t: T) {
 #[inline(always)]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_promotable]
+#[cfg_attr(not(bootstrap), rustc_const_stable(feature = "const_size_of", since = "1.32.0"))]
 pub const fn size_of<T>() -> usize {
     intrinsics::size_of::<T>()
 }
@@ -371,6 +372,7 @@ pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize {
 #[inline(always)]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_promotable]
+#[cfg_attr(not(bootstrap), rustc_const_stable(feature = "const_align_of", since = "1.32.0"))]
 pub const fn align_of<T>() -> usize {
     intrinsics::min_align_of::<T>()
 }
@@ -453,6 +455,7 @@ pub fn align_of_val<T: ?Sized>(val: &T) -> usize {
 /// ```
 #[inline]
 #[stable(feature = "needs_drop", since = "1.21.0")]
+#[cfg_attr(not(bootstrap), rustc_const_stable(feature = "const_needs_drop", since = "1.36.0"))]
 pub const fn needs_drop<T>() -> bool {
     intrinsics::needs_drop::<T>()
 }
diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs
index d1f518d52dd..5a97aa4acfa 100644
--- a/src/libcore/num/mod.rs
+++ b/src/libcore/num/mod.rs
@@ -60,6 +60,10 @@ assert_eq!(size_of::<Option<core::num::", stringify!($Ty), ">>(), size_of::<", s
                 ///
                 /// The value must not be zero.
                 #[$stability]
+                #[cfg_attr(
+                    not(bootstrap),
+                    rustc_const_stable(feature = "nonzero", since = "1.34.0"),
+                )]
                 #[inline]
                 pub const unsafe fn new_unchecked(n: $Int) -> Self {
                     $Ty(n)
@@ -80,6 +84,10 @@ assert_eq!(size_of::<Option<core::num::", stringify!($Ty), ">>(), size_of::<", s
                 /// Returns the value as a primitive type.
                 #[$stability]
                 #[inline]
+                #[cfg_attr(
+                    not(bootstrap),
+                    rustc_const_stable(feature = "nonzero", since = "1.34.0"),
+                )]
                 pub const fn get(self) -> $Int {
                     self.0
                 }
@@ -255,6 +263,10 @@ $EndFeature, "
             #[stable(feature = "rust1", since = "1.0.0")]
             #[inline(always)]
             #[rustc_promotable]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_min_value", since = "1.32.0"),
+            )]
             pub const fn min_value() -> Self {
                 !0 ^ ((!0 as $UnsignedT) >> 1) as Self
             }
@@ -274,6 +286,10 @@ $EndFeature, "
             #[stable(feature = "rust1", since = "1.0.0")]
             #[inline(always)]
             #[rustc_promotable]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_max_value", since = "1.32.0"),
+            )]
             pub const fn max_value() -> Self {
                 !Self::min_value()
             }
@@ -323,6 +339,10 @@ $EndFeature, "
 ```
 "),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_int_methods", since = "1.32.0"),
+            )]
             #[inline]
             pub const fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() }
         }
@@ -338,6 +358,10 @@ Basic usage:
 ", $Feature, "assert_eq!(", stringify!($SelfT), "::max_value().count_zeros(), 1);", $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_int_methods", since = "1.32.0"),
+            )]
             #[inline]
             pub const fn count_zeros(self) -> u32 {
                 (!self).count_ones()
@@ -358,6 +382,10 @@ assert_eq!(n.leading_zeros(), 0);",
 $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_int_methods", since = "1.32.0"),
+            )]
             #[inline]
             pub const fn leading_zeros(self) -> u32 {
                 (self as $UnsignedT).leading_zeros()
@@ -378,6 +406,10 @@ assert_eq!(n.trailing_zeros(), 2);",
 $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_int_methods", since = "1.32.0"),
+            )]
             #[inline]
             pub const fn trailing_zeros(self) -> u32 {
                 (self as $UnsignedT).trailing_zeros()
@@ -401,6 +433,10 @@ let m = ", $rot_result, ";
 assert_eq!(n.rotate_left(", $rot, "), m);
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_int_methods", since = "1.32.0"),
+            )]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -427,6 +463,10 @@ let m = ", $rot_op, ";
 assert_eq!(n.rotate_right(", $rot, "), m);
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_int_methods", since = "1.32.0"),
+            )]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -450,6 +490,10 @@ let m = n.swap_bytes();
 assert_eq!(m, ", $swapped, ");
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_int_methods", since = "1.32.0"),
+            )]
             #[inline]
             pub const fn swap_bytes(self) -> Self {
                 (self as $UnsignedT).swap_bytes() as Self
@@ -470,6 +514,10 @@ let m = n.reverse_bits();
 assert_eq!(m, ", $reversed, ");
 ```"),
             #[stable(feature = "reverse_bits", since = "1.37.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_int_methods", since = "1.32.0"),
+            )]
             #[inline]
             #[must_use]
             pub const fn reverse_bits(self) -> Self {
@@ -497,6 +545,10 @@ if cfg!(target_endian = \"big\") {
 $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_int_conversions", since = "1.32.0"),
+            )]
             #[inline]
             pub const fn from_be(x: Self) -> Self {
                 #[cfg(target_endian = "big")]
@@ -530,6 +582,10 @@ if cfg!(target_endian = \"little\") {
 $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_int_conversions", since = "1.32.0"),
+            )]
             #[inline]
             pub const fn from_le(x: Self) -> Self {
                 #[cfg(target_endian = "little")]
@@ -563,6 +619,10 @@ if cfg!(target_endian = \"big\") {
 $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_int_conversions", since = "1.32.0"),
+            )]
             #[inline]
             pub const fn to_be(self) -> Self { // or not to be?
                 #[cfg(target_endian = "big")]
@@ -596,6 +656,10 @@ if cfg!(target_endian = \"little\") {
 $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_int_conversions", since = "1.32.0"),
+            )]
             #[inline]
             pub const fn to_le(self) -> Self {
                 #[cfg(target_endian = "little")]
@@ -948,7 +1012,11 @@ $EndFeature, "
 ```"),
 
             #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_unstable(feature = "const_saturating_int_methods")]
+            #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_saturating_int_methods"))]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_unstable(feature = "const_saturating_int_methods", issue = "53718"),
+            )]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -974,7 +1042,11 @@ assert_eq!(", stringify!($SelfT), "::max_value().saturating_sub(-1), ", stringif
 $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_unstable(feature = "const_saturating_int_methods")]
+            #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_saturating_int_methods"))]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_unstable(feature = "const_saturating_int_methods", issue = "53718"),
+            )]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -1114,6 +1186,10 @@ assert_eq!(", stringify!($SelfT), "::max_value().wrapping_add(2), ", stringify!(
 $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_int_methods", since = "1.32.0"),
+            )]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -1137,6 +1213,10 @@ stringify!($SelfT), "::max_value());",
 $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_int_methods", since = "1.32.0"),
+            )]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -1159,6 +1239,10 @@ assert_eq!(11i8.wrapping_mul(12), -124);",
 $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_int_methods", since = "1.32.0"),
+            )]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -1303,6 +1387,10 @@ assert_eq!(", stringify!($SelfT), "::min_value().wrapping_neg(), ", stringify!($
 $EndFeature, "
 ```"),
             #[stable(feature = "num_wrapping", since = "1.2.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_int_methods", since = "1.32.0"),
+            )]
             #[inline]
             pub const fn wrapping_neg(self) -> Self {
                 self.overflowing_neg().0
@@ -1328,6 +1416,10 @@ assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(128), -1);",
 $EndFeature, "
 ```"),
             #[stable(feature = "num_wrapping", since = "1.2.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_int_methods", since = "1.32.0"),
+            )]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -1359,6 +1451,10 @@ assert_eq!((-128i16).wrapping_shr(64), -128);",
 $EndFeature, "
 ```"),
             #[stable(feature = "num_wrapping", since = "1.2.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_int_methods", since = "1.32.0"),
+            )]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -1392,6 +1488,10 @@ assert_eq!((-128i8).wrapping_abs() as u8, 128);",
 $EndFeature, "
 ```"),
             #[stable(feature = "no_panic_abs", since = "1.13.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_int_methods", since = "1.32.0"),
+            )]
             #[inline]
             pub const fn wrapping_abs(self) -> Self {
                 // sign is -1 (all ones) for negative numbers, 0 otherwise.
@@ -1466,6 +1566,10 @@ assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (", stringify!($Sel
 "::MIN, true));", $EndFeature, "
 ```"),
             #[stable(feature = "wrapping", since = "1.7.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_int_methods", since = "1.32.0"),
+            )]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -1493,6 +1597,10 @@ assert_eq!(", stringify!($SelfT), "::MIN.overflowing_sub(1), (", stringify!($Sel
 "::MAX, true));", $EndFeature, "
 ```"),
             #[stable(feature = "wrapping", since = "1.7.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_int_methods", since = "1.32.0"),
+            )]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -1518,6 +1626,10 @@ assert_eq!(1_000_000_000i32.overflowing_mul(10), (1410065408, true));",
 $EndFeature, "
 ```"),
             #[stable(feature = "wrapping", since = "1.7.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_int_methods", since = "1.32.0"),
+            )]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -1685,6 +1797,10 @@ assert_eq!(", stringify!($SelfT), "::MIN.overflowing_neg(), (", stringify!($Self
 ```"),
             #[inline]
             #[stable(feature = "wrapping", since = "1.7.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_int_methods", since = "1.32.0"),
+            )]
             pub const fn overflowing_neg(self) -> (Self, bool) {
                 ((!self).wrapping_add(1), self == Self::min_value())
             }
@@ -1707,6 +1823,10 @@ assert_eq!(0x1i32.overflowing_shl(36), (0x10, true));",
 $EndFeature, "
 ```"),
             #[stable(feature = "wrapping", since = "1.7.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_int_methods", since = "1.32.0"),
+            )]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -1732,6 +1852,10 @@ assert_eq!(0x10i32.overflowing_shr(36), (0x1, true));",
 $EndFeature, "
 ```"),
             #[stable(feature = "wrapping", since = "1.7.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_int_methods", since = "1.32.0"),
+            )]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -1760,6 +1884,10 @@ assert_eq!((", stringify!($SelfT), "::min_value()).overflowing_abs(), (", string
 $EndFeature, "
 ```"),
             #[stable(feature = "no_panic_abs", since = "1.13.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_int_methods", since = "1.32.0"),
+            )]
             #[inline]
             pub const fn overflowing_abs(self) -> (Self, bool) {
                 (self.wrapping_abs(), self == Self::min_value())
@@ -1964,6 +2092,10 @@ assert_eq!((-10", stringify!($SelfT), ").abs(), 10);",
 $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_int_methods", since = "1.32.0"),
+            )]
             #[inline]
             #[rustc_inherit_overflow_checks]
             pub const fn abs(self) -> Self {
@@ -2006,7 +2138,11 @@ assert_eq!((-10", stringify!($SelfT), ").signum(), -1);",
 $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
-            #[rustc_const_unstable(feature = "const_int_sign")]
+            #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_int_sign"))]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_unstable(feature = "const_int_sign", issue = "53718"),
+            )]
             #[inline]
             pub const fn signum(self) -> Self {
                 (self > 0) as Self - (self < 0) as Self
@@ -2027,6 +2163,10 @@ assert!(!(-10", stringify!($SelfT), ").is_positive());",
 $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_int_methods", since = "1.32.0"),
+            )]
             #[inline]
             pub const fn is_positive(self) -> bool { self > 0 }
         }
@@ -2045,6 +2185,10 @@ assert!(!10", stringify!($SelfT), ".is_negative());",
 $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_int_methods", since = "1.32.0"),
+            )]
             #[inline]
             pub const fn is_negative(self) -> bool { self < 0 }
         }
@@ -2062,7 +2206,11 @@ let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes();
 assert_eq!(bytes, ", $be_bytes, ");
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion")]
+            #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_int_conversion"))]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_unstable(feature = "const_int_conversion", issue = "53718"),
+            )]
             #[inline]
             pub const fn to_be_bytes(self) -> [u8; mem::size_of::<Self>()] {
                 self.to_be().to_ne_bytes()
@@ -2082,7 +2230,11 @@ let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes();
 assert_eq!(bytes, ", $le_bytes, ");
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion")]
+            #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_int_conversion"))]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_unstable(feature = "const_int_conversion", issue = "53718"),
+            )]
             #[inline]
             pub const fn to_le_bytes(self) -> [u8; mem::size_of::<Self>()] {
                 self.to_le().to_ne_bytes()
@@ -2117,7 +2269,11 @@ assert_eq!(
 );
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion")]
+            #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_int_conversion"))]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_unstable(feature = "const_int_conversion", issue = "53718"),
+            )]
             #[inline]
             pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
                 // SAFETY: integers are plain old datatypes so we can always transmute them to
@@ -2151,7 +2307,11 @@ fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
 }
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion")]
+            #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_int_conversion"))]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_unstable(feature = "const_int_conversion", issue = "53718"),
+            )]
             #[inline]
             pub const fn from_be_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
                 Self::from_be(Self::from_ne_bytes(bytes))
@@ -2184,7 +2344,11 @@ fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
 }
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion")]
+            #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_int_conversion"))]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_unstable(feature = "const_int_conversion", issue = "53718"),
+            )]
             #[inline]
             pub const fn from_le_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
                 Self::from_le(Self::from_ne_bytes(bytes))
@@ -2227,7 +2391,11 @@ fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
 }
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion")]
+            #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_int_conversion"))]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_unstable(feature = "const_int_conversion", issue = "53718"),
+            )]
             #[inline]
             pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
                 // SAFETY: integers are plain old datatypes so we can always transmute to them
@@ -2321,6 +2489,10 @@ Basic usage:
             #[stable(feature = "rust1", since = "1.0.0")]
             #[rustc_promotable]
             #[inline(always)]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_min_value", since = "1.32.0"),
+            )]
             pub const fn min_value() -> Self { 0 }
         }
 
@@ -2338,6 +2510,10 @@ stringify!($MaxV), ");", $EndFeature, "
             #[stable(feature = "rust1", since = "1.0.0")]
             #[rustc_promotable]
             #[inline(always)]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_max_value", since = "1.32.0"),
+            )]
             pub const fn max_value() -> Self { !0 }
         }
 
@@ -2384,6 +2560,10 @@ Basic usage:
 assert_eq!(n.count_ones(), 3);", $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_math", since = "1.32.0"),
+            )]
             #[inline]
             pub const fn count_ones(self) -> u32 {
                 intrinsics::ctpop(self as $ActualT) as u32
@@ -2401,6 +2581,10 @@ Basic usage:
 ", $Feature, "assert_eq!(", stringify!($SelfT), "::max_value().count_zeros(), 0);", $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_math", since = "1.32.0"),
+            )]
             #[inline]
             pub const fn count_zeros(self) -> u32 {
                 (!self).count_ones()
@@ -2420,6 +2604,10 @@ Basic usage:
 assert_eq!(n.leading_zeros(), 2);", $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_math", since = "1.32.0"),
+            )]
             #[inline]
             pub const fn leading_zeros(self) -> u32 {
                 intrinsics::ctlz(self as $ActualT) as u32
@@ -2440,6 +2628,10 @@ Basic usage:
 assert_eq!(n.trailing_zeros(), 3);", $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_math", since = "1.32.0"),
+            )]
             #[inline]
             pub const fn trailing_zeros(self) -> u32 {
                 intrinsics::cttz(self) as u32
@@ -2463,6 +2655,10 @@ let m = ", $rot_result, ";
 assert_eq!(n.rotate_left(", $rot, "), m);
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_math", since = "1.32.0"),
+            )]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -2489,6 +2685,10 @@ let m = ", $rot_op, ";
 assert_eq!(n.rotate_right(", $rot, "), m);
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_math", since = "1.32.0"),
+            )]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -2512,6 +2712,10 @@ let m = n.swap_bytes();
 assert_eq!(m, ", $swapped, ");
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_math", since = "1.32.0"),
+            )]
             #[inline]
             pub const fn swap_bytes(self) -> Self {
                 intrinsics::bswap(self as $ActualT) as Self
@@ -2532,6 +2736,10 @@ let m = n.reverse_bits();
 assert_eq!(m, ", $reversed, ");
 ```"),
             #[stable(feature = "reverse_bits", since = "1.37.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_math", since = "1.32.0"),
+            )]
             #[inline]
             #[must_use]
             pub const fn reverse_bits(self) -> Self {
@@ -2559,6 +2767,10 @@ if cfg!(target_endian = \"big\") {
 }", $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_math", since = "1.32.0"),
+            )]
             #[inline]
             pub const fn from_be(x: Self) -> Self {
                 #[cfg(target_endian = "big")]
@@ -2592,6 +2804,10 @@ if cfg!(target_endian = \"little\") {
 }", $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_math", since = "1.32.0"),
+            )]
             #[inline]
             pub const fn from_le(x: Self) -> Self {
                 #[cfg(target_endian = "little")]
@@ -2625,6 +2841,10 @@ if cfg!(target_endian = \"big\") {
 }", $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_math", since = "1.32.0"),
+            )]
             #[inline]
             pub const fn to_be(self) -> Self { // or not to be?
                 #[cfg(target_endian = "big")]
@@ -2658,6 +2878,10 @@ if cfg!(target_endian = \"little\") {
 }", $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_math", since = "1.32.0"),
+            )]
             #[inline]
             pub const fn to_le(self) -> Self {
                 #[cfg(target_endian = "little")]
@@ -2963,7 +3187,11 @@ assert_eq!(200u8.saturating_add(127), 255);", $EndFeature, "
             #[stable(feature = "rust1", since = "1.0.0")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
-            #[rustc_const_unstable(feature = "const_saturating_int_methods")]
+            #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_saturating_int_methods"))]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_unstable(feature = "const_saturating_int_methods", issue = "53718"),
+            )]
             #[inline]
             pub const fn saturating_add(self, rhs: Self) -> Self {
                 intrinsics::saturating_add(self, rhs)
@@ -2985,7 +3213,11 @@ assert_eq!(13", stringify!($SelfT), ".saturating_sub(127), 0);", $EndFeature, "
             #[stable(feature = "rust1", since = "1.0.0")]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
-            #[rustc_const_unstable(feature = "const_saturating_int_methods")]
+            #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_saturating_int_methods"))]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_unstable(feature = "const_saturating_int_methods", issue = "53718"),
+            )]
             #[inline]
             pub const fn saturating_sub(self, rhs: Self) -> Self {
                 intrinsics::saturating_sub(self, rhs)
@@ -3057,6 +3289,10 @@ assert_eq!(200", stringify!($SelfT), ".wrapping_add(", stringify!($SelfT), "::ma
 $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0"),
+            )]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -3079,6 +3315,10 @@ assert_eq!(100", stringify!($SelfT), ".wrapping_sub(", stringify!($SelfT), "::ma
 $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0"),
+            )]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -3102,6 +3342,10 @@ $EndFeature, "
         /// assert_eq!(25u8.wrapping_mul(12), 44);
         /// ```
         #[stable(feature = "rust1", since = "1.0.0")]
+        #[cfg_attr(
+            not(bootstrap),
+            rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0"),
+        )]
         #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
         #[inline]
@@ -3231,6 +3475,10 @@ assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0);
         /// assert_eq!((-128i8).wrapping_neg(), -128);
         /// ```
         #[stable(feature = "num_wrapping", since = "1.2.0")]
+        #[cfg_attr(
+            not(bootstrap),
+            rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0"),
+        )]
         #[inline]
         pub const fn wrapping_neg(self) -> Self {
             self.overflowing_neg().0
@@ -3257,6 +3505,10 @@ Basic usage:
 assert_eq!(1", stringify!($SelfT), ".wrapping_shl(128), 1);", $EndFeature, "
 ```"),
             #[stable(feature = "num_wrapping", since = "1.2.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0"),
+            )]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -3290,6 +3542,10 @@ Basic usage:
 assert_eq!(128", stringify!($SelfT), ".wrapping_shr(128), 128);", $EndFeature, "
 ```"),
             #[stable(feature = "num_wrapping", since = "1.2.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0"),
+            )]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -3359,6 +3615,10 @@ assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false));
 assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (0, true));", $EndFeature, "
 ```"),
             #[stable(feature = "wrapping", since = "1.7.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0"),
+            )]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -3387,6 +3647,10 @@ assert_eq!(0", stringify!($SelfT), ".overflowing_sub(1), (", stringify!($SelfT),
 $EndFeature, "
 ```"),
             #[stable(feature = "wrapping", since = "1.7.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0"),
+            )]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -3414,6 +3678,10 @@ $EndFeature, "
         /// assert_eq!(1_000_000_000u32.overflowing_mul(10), (1410065408, true));
         /// ```
         #[stable(feature = "wrapping", since = "1.7.0")]
+        #[cfg_attr(
+            not(bootstrap),
+            rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0"),
+        )]
         #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
         #[inline]
@@ -3559,6 +3827,10 @@ assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2i32 as ", stringify!(
 ```"),
             #[inline]
             #[stable(feature = "wrapping", since = "1.7.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0"),
+            )]
             pub const fn overflowing_neg(self) -> (Self, bool) {
                 ((!self).wrapping_add(1), self != 0)
             }
@@ -3582,6 +3854,10 @@ Basic usage
 assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(132), (0x10, true));", $EndFeature, "
 ```"),
             #[stable(feature = "wrapping", since = "1.7.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0"),
+            )]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -3608,6 +3884,10 @@ Basic usage
 assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(132), (0x1, true));", $EndFeature, "
 ```"),
             #[stable(feature = "wrapping", since = "1.7.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0"),
+            )]
             #[must_use = "this returns the result of the operation, \
                           without modifying the original"]
             #[inline]
@@ -3773,6 +4053,10 @@ Basic usage:
 assert!(!10", stringify!($SelfT), ".is_power_of_two());", $EndFeature, "
 ```"),
             #[stable(feature = "rust1", since = "1.0.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_is_power_of_two", since = "1.32.0"),
+            )]
             #[inline]
             pub const fn is_power_of_two(self) -> bool {
                 self.count_ones() == 1
@@ -3884,7 +4168,11 @@ let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes();
 assert_eq!(bytes, ", $be_bytes, ");
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion")]
+            #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_int_conversion"))]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_unstable(feature = "const_int_conversion", issue = "53718"),
+            )]
             #[inline]
             pub const fn to_be_bytes(self) -> [u8; mem::size_of::<Self>()] {
                 self.to_be().to_ne_bytes()
@@ -3904,7 +4192,11 @@ let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes();
 assert_eq!(bytes, ", $le_bytes, ");
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion")]
+            #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_int_conversion"))]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_unstable(feature = "const_int_conversion", issue = "53718"),
+            )]
             #[inline]
             pub const fn to_le_bytes(self) -> [u8; mem::size_of::<Self>()] {
                 self.to_le().to_ne_bytes()
@@ -3939,7 +4231,11 @@ assert_eq!(
 );
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion")]
+            #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_int_conversion"))]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_unstable(feature = "const_int_conversion", issue = "53718"),
+            )]
             #[inline]
             pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
                 // SAFETY: integers are plain old datatypes so we can always transmute them to
@@ -3973,7 +4269,11 @@ fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
 }
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion")]
+            #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_int_conversion"))]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_unstable(feature = "const_int_conversion", issue = "53718"),
+            )]
             #[inline]
             pub const fn from_be_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
                 Self::from_be(Self::from_ne_bytes(bytes))
@@ -4006,7 +4306,11 @@ fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
 }
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion")]
+            #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_int_conversion"))]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_unstable(feature = "const_int_conversion", issue = "53718"),
+            )]
             #[inline]
             pub const fn from_le_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
                 Self::from_le(Self::from_ne_bytes(bytes))
@@ -4049,7 +4353,11 @@ fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT),
 }
 ```"),
             #[stable(feature = "int_to_from_bytes", since = "1.32.0")]
-            #[rustc_const_unstable(feature = "const_int_conversion")]
+            #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_int_conversion"))]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_unstable(feature = "const_int_conversion", issue = "53718"),
+            )]
             #[inline]
             pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
                 // SAFETY: integers are plain old datatypes so we can always transmute to them
diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs
index 0ddfbd02aa5..46398dd2f82 100644
--- a/src/libcore/num/wrapping.rs
+++ b/src/libcore/num/wrapping.rs
@@ -530,6 +530,10 @@ assert_eq!(n.trailing_zeros(), 3);
             /// assert_eq!(m, Wrapping(-22016));
             /// ```
             #[stable(feature = "reverse_bits", since = "1.37.0")]
+            #[cfg_attr(
+                not(bootstrap),
+                rustc_const_stable(feature = "const_reverse_bits", since = "1.37.0"),
+            )]
             #[inline]
             #[must_use]
             pub const fn reverse_bits(self) -> Self {
diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs
index a2250337a4d..54ce2917a36 100644
--- a/src/libcore/ops/range.rs
+++ b/src/libcore/ops/range.rs
@@ -398,6 +398,7 @@ impl<Idx> RangeInclusive<Idx> {
     #[stable(feature = "inclusive_range_methods", since = "1.27.0")]
     #[inline]
     #[rustc_promotable]
+    #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "const_range_new", since = "1.32.0"))]
     pub const fn new(start: Idx, end: Idx) -> Self {
         Self { start, end, is_empty: None }
     }
@@ -421,6 +422,10 @@ impl<Idx> RangeInclusive<Idx> {
     /// assert_eq!((3..=5).start(), &3);
     /// ```
     #[stable(feature = "inclusive_range_methods", since = "1.27.0")]
+    #[cfg_attr(
+        not(bootstrap),
+        rustc_const_stable(feature = "const_inclusive_range_methods", since = "1.32.0"),
+    )]
     #[inline]
     pub const fn start(&self) -> &Idx {
         &self.start
@@ -445,6 +450,10 @@ impl<Idx> RangeInclusive<Idx> {
     /// assert_eq!((3..=5).end(), &5);
     /// ```
     #[stable(feature = "inclusive_range_methods", since = "1.27.0")]
+    #[cfg_attr(
+        not(bootstrap),
+        rustc_const_stable(feature = "const_inclusive_range_methods", since = "1.32.0"),
+    )]
     #[inline]
     pub const fn end(&self) -> &Idx {
         &self.end
diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs
index 24ffa348329..33c23233fd1 100644
--- a/src/libcore/ptr/mod.rs
+++ b/src/libcore/ptr/mod.rs
@@ -198,6 +198,7 @@ unsafe fn real_drop_in_place<T: ?Sized>(to_drop: &mut T) {
 #[inline(always)]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_promotable]
+#[cfg_attr(not(bootstrap), rustc_const_stable(feature = "const_ptr_null", since = "1.32.0"))]
 pub const fn null<T>() -> *const T {
     0 as *const T
 }
@@ -215,6 +216,7 @@ pub const fn null<T>() -> *const T {
 #[inline(always)]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_promotable]
+#[cfg_attr(not(bootstrap), rustc_const_stable(feature = "const_ptr_null", since = "1.32.0"))]
 pub const fn null_mut<T>() -> *mut T {
     0 as *mut T
 }
@@ -1060,6 +1062,7 @@ impl<T: ?Sized> *const T {
 
     /// Casts to a pointer of another type.
     #[stable(feature = "ptr_cast", since = "1.38.0")]
+    #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "const_ptr_cast", since = "1.38.0"))]
     #[inline]
     pub const fn cast<U>(self) -> *const U {
         self as _
@@ -1307,7 +1310,11 @@ impl<T: ?Sized> *const T {
     /// }
     /// ```
     #[unstable(feature = "ptr_offset_from", issue = "41079")]
-    #[rustc_const_unstable(feature = "const_ptr_offset_from")]
+    #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ptr_offset_from"))]
+    #[cfg_attr(
+        not(bootstrap),
+        rustc_const_unstable(feature = "const_ptr_offset_from", issue = "41079"),
+    )]
     #[inline]
     pub const unsafe fn offset_from(self, origin: *const T) -> isize
     where
@@ -1763,6 +1770,7 @@ impl<T: ?Sized> *mut T {
 
     /// Casts to a pointer of another type.
     #[stable(feature = "ptr_cast", since = "1.38.0")]
+    #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "const_ptr_cast", since = "1.38.0"))]
     #[inline]
     pub const fn cast<U>(self) -> *mut U {
         self as _
@@ -2049,7 +2057,11 @@ impl<T: ?Sized> *mut T {
     /// }
     /// ```
     #[unstable(feature = "ptr_offset_from", issue = "41079")]
-    #[rustc_const_unstable(feature = "const_ptr_offset_from")]
+    #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_ptr_offset_from"))]
+    #[cfg_attr(
+        not(bootstrap),
+        rustc_const_unstable(feature = "const_ptr_offset_from", issue = "41079"),
+    )]
     #[inline]
     pub const unsafe fn offset_from(self, origin: *const T) -> isize
     where
diff --git a/src/libcore/ptr/non_null.rs b/src/libcore/ptr/non_null.rs
index a121389bef3..d1d97d7b332 100644
--- a/src/libcore/ptr/non_null.rs
+++ b/src/libcore/ptr/non_null.rs
@@ -66,6 +66,10 @@ impl<T: Sized> NonNull<T> {
     /// sentinel value. Types that lazily allocate must track initialization by
     /// some other means.
     #[stable(feature = "nonnull", since = "1.25.0")]
+    #[cfg_attr(
+        not(bootstrap),
+        rustc_const_stable(feature = "const_nonnull_dangling", since = "1.32.0"),
+    )]
     #[inline]
     pub const fn dangling() -> Self {
         unsafe {
@@ -82,6 +86,10 @@ impl<T: ?Sized> NonNull<T> {
     ///
     /// `ptr` must be non-null.
     #[stable(feature = "nonnull", since = "1.25.0")]
+    #[cfg_attr(
+        not(bootstrap),
+        rustc_const_stable(feature = "const_nonnull_new_unchecked", since = "1.32.0"),
+    )]
     #[inline]
     pub const unsafe fn new_unchecked(ptr: *mut T) -> Self {
         NonNull { pointer: ptr as _ }
@@ -96,6 +104,10 @@ impl<T: ?Sized> NonNull<T> {
 
     /// Acquires the underlying `*mut` pointer.
     #[stable(feature = "nonnull", since = "1.25.0")]
+    #[cfg_attr(
+        not(bootstrap),
+        rustc_const_stable(feature = "const_nonnull_as_ptr", since = "1.32.0"),
+    )]
     #[inline]
     pub const fn as_ptr(self) -> *mut T {
         self.pointer as *mut T
@@ -125,6 +137,10 @@ impl<T: ?Sized> NonNull<T> {
 
     /// Casts to a pointer of another type.
     #[stable(feature = "nonnull_cast", since = "1.27.0")]
+    #[cfg_attr(
+        not(bootstrap),
+        rustc_const_stable(feature = "const_nonnull_cast", since = "1.32.0"),
+    )]
     #[inline]
     pub const fn cast<U>(self) -> NonNull<U> {
         unsafe { NonNull::new_unchecked(self.as_ptr() as *mut U) }
diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs
index c8fe9f98613..a8e500d256f 100644
--- a/src/libcore/slice/mod.rs
+++ b/src/libcore/slice/mod.rs
@@ -62,6 +62,7 @@ impl<T> [T] {
     /// assert_eq!(a.len(), 3);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "const_slice_len", since = "1.32.0"))]
     #[inline]
     // SAFETY: const sound because we transmute out the length field as a usize (which it must be)
     #[allow(unused_attributes)]
@@ -81,6 +82,10 @@ impl<T> [T] {
     /// assert!(!a.is_empty());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(
+        not(bootstrap),
+        rustc_const_stable(feature = "const_slice_is_empty", since = "1.32.0"),
+    )]
     #[inline]
     pub const fn is_empty(&self) -> bool {
         self.len() == 0
@@ -376,6 +381,10 @@ impl<T> [T] {
     ///
     /// [`as_mut_ptr`]: #method.as_mut_ptr
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(
+        not(bootstrap),
+        rustc_const_stable(feature = "const_slice_as_ptr", since = "1.32.0"),
+    )]
     #[inline]
     pub const fn as_ptr(&self) -> *const T {
         self as *const [T] as *const T
diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs
index b2a420f3c43..6d225a25f20 100644
--- a/src/libcore/str/mod.rs
+++ b/src/libcore/str/mod.rs
@@ -2090,6 +2090,7 @@ impl str {
     /// assert_eq!("Æ’oo".chars().count(), 3);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "const_str_len", since = "1.32.0"))]
     #[inline]
     pub const fn len(&self) -> usize {
         self.as_bytes().len()
@@ -2110,6 +2111,10 @@ impl str {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(
+        not(bootstrap),
+        rustc_const_stable(feature = "const_str_is_empty", since = "1.32.0"),
+    )]
     pub const fn is_empty(&self) -> bool {
         self.len() == 0
     }
@@ -2166,6 +2171,7 @@ impl str {
     /// assert_eq!(b"bors", bytes);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "str_as_bytes", since = "1.32.0"))]
     #[inline(always)]
     // SAFETY: const sound because we transmute two types with the same layout
     #[allow(unused_attributes)]
@@ -2239,6 +2245,7 @@ impl str {
     /// let ptr = s.as_ptr();
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "rustc_str_as_ptr", since = "1.32.0"))]
     #[inline]
     pub const fn as_ptr(&self) -> *const u8 {
         self as *const str as *const u8
diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs
index 6e1aac00c7b..7756335ee20 100644
--- a/src/libcore/sync/atomic.rs
+++ b/src/libcore/sync/atomic.rs
@@ -331,6 +331,7 @@ impl AtomicBool {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "const_atomic_new", since = "1.32.0"))]
     pub const fn new(v: bool) -> AtomicBool {
         AtomicBool { v: UnsafeCell::new(v as u8) }
     }
@@ -855,6 +856,7 @@ impl<T> AtomicPtr<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "const_atomic_new", since = "1.32.0"))]
     pub const fn new(p: *mut T) -> AtomicPtr<T> {
         AtomicPtr { p: UnsafeCell::new(p) }
     }
@@ -1183,6 +1185,7 @@ macro_rules! atomic_int {
      $stable_access:meta,
      $stable_from:meta,
      $stable_nand:meta,
+     $const_stable:meta,
      $stable_init_const:meta,
      $s_int_type:expr, $int_ref:expr,
      $extra_feature:expr,
@@ -1258,6 +1261,7 @@ let atomic_forty_two = ", stringify!($atomic_type), "::new(42);
 ```"),
                 #[inline]
                 #[$stable]
+                #[cfg_attr(not(bootstrap), $const_stable)]
                 pub const fn new(v: $int_type) -> Self {
                     $atomic_type {v: UnsafeCell::new(v)}
                 }
@@ -1978,6 +1982,7 @@ atomic_int! {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
+    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
     "i8", "../../../std/primitive.i8.html",
     "",
@@ -1995,6 +2000,7 @@ atomic_int! {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
+    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
     "u8", "../../../std/primitive.u8.html",
     "",
@@ -2012,6 +2018,7 @@ atomic_int! {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
+    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
     "i16", "../../../std/primitive.i16.html",
     "",
@@ -2029,6 +2036,7 @@ atomic_int! {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
+    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
     "u16", "../../../std/primitive.u16.html",
     "",
@@ -2046,6 +2054,7 @@ atomic_int! {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
+    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
     "i32", "../../../std/primitive.i32.html",
     "",
@@ -2063,6 +2072,7 @@ atomic_int! {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
+    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
     "u32", "../../../std/primitive.u32.html",
     "",
@@ -2080,6 +2090,7 @@ atomic_int! {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
+    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
     "i64", "../../../std/primitive.i64.html",
     "",
@@ -2097,6 +2108,7 @@ atomic_int! {
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
     stable(feature = "integer_atomics_stable", since = "1.34.0"),
+    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
     "u64", "../../../std/primitive.u64.html",
     "",
@@ -2114,6 +2126,7 @@ atomic_int! {
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
     "i128", "../../../std/primitive.i128.html",
     "#![feature(integer_atomics)]\n\n",
@@ -2131,6 +2144,7 @@ atomic_int! {
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
     unstable(feature = "integer_atomics", issue = "32976"),
+    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     unstable(feature = "integer_atomics", issue = "32976"),
     "u128", "../../../std/primitive.u128.html",
     "#![feature(integer_atomics)]\n\n",
@@ -2163,6 +2177,7 @@ atomic_int!{
     stable(feature = "atomic_access", since = "1.15.0"),
     stable(feature = "atomic_from", since = "1.23.0"),
     stable(feature = "atomic_nand", since = "1.27.0"),
+    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     stable(feature = "rust1", since = "1.0.0"),
     "isize", "../../../std/primitive.isize.html",
     "",
@@ -2180,6 +2195,7 @@ atomic_int!{
     stable(feature = "atomic_access", since = "1.15.0"),
     stable(feature = "atomic_from", since = "1.23.0"),
     stable(feature = "atomic_nand", since = "1.27.0"),
+    rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
     stable(feature = "rust1", since = "1.0.0"),
     "usize", "../../../std/primitive.usize.html",
     "",
diff --git a/src/libcore/task/wake.rs b/src/libcore/task/wake.rs
index 0759ff93ea8..c1e45f189b7 100644
--- a/src/libcore/task/wake.rs
+++ b/src/libcore/task/wake.rs
@@ -39,6 +39,7 @@ impl RawWaker {
     /// function in the `vtable` of the underlying `RawWaker` will be called.
     #[rustc_promotable]
     #[stable(feature = "futures_api", since = "1.36.0")]
+    #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "futures_api", since = "1.36.0"))]
     pub const fn new(data: *const (), vtable: &'static RawWakerVTable) -> RawWaker {
         RawWaker { data, vtable }
     }
@@ -151,6 +152,7 @@ impl RawWakerVTable {
     // FIXME: remove whenever we have a stable way to accept fn pointers from const fn
     // (see https://github.com/rust-rfcs/const-eval/issues/19#issuecomment-472799062)
     #[rustc_allow_const_fn_ptr]
+    #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "futures_api", since = "1.36.0"))]
     pub const fn new(
         clone: unsafe fn(*const ()) -> RawWaker,
         wake: unsafe fn(*const ()),
diff --git a/src/libcore/time.rs b/src/libcore/time.rs
index 70ec1e42fd7..7d04cfb5da5 100644
--- a/src/libcore/time.rs
+++ b/src/libcore/time.rs
@@ -130,6 +130,7 @@ impl Duration {
     /// ```
     #[stable(feature = "duration", since = "1.3.0")]
     #[inline]
+    #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "duration_consts", since = "1.32.0"))]
     pub fn new(secs: u64, nanos: u32) -> Duration {
         let secs =
             secs.checked_add((nanos / NANOS_PER_SEC) as u64).expect("overflow in Duration::new");
@@ -152,6 +153,7 @@ impl Duration {
     #[stable(feature = "duration", since = "1.3.0")]
     #[inline]
     #[rustc_promotable]
+    #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "duration_consts", since = "1.32.0"))]
     pub const fn from_secs(secs: u64) -> Duration {
         Duration { secs, nanos: 0 }
     }
@@ -171,6 +173,7 @@ impl Duration {
     #[stable(feature = "duration", since = "1.3.0")]
     #[inline]
     #[rustc_promotable]
+    #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "duration_consts", since = "1.32.0"))]
     pub const fn from_millis(millis: u64) -> Duration {
         Duration {
             secs: millis / MILLIS_PER_SEC,
@@ -193,6 +196,7 @@ impl Duration {
     #[stable(feature = "duration_from_micros", since = "1.27.0")]
     #[inline]
     #[rustc_promotable]
+    #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "duration_consts", since = "1.32.0"))]
     pub const fn from_micros(micros: u64) -> Duration {
         Duration {
             secs: micros / MICROS_PER_SEC,
@@ -215,6 +219,7 @@ impl Duration {
     #[stable(feature = "duration_extras", since = "1.27.0")]
     #[inline]
     #[rustc_promotable]
+    #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "duration_consts", since = "1.32.0"))]
     pub const fn from_nanos(nanos: u64) -> Duration {
         Duration {
             secs: nanos / (NANOS_PER_SEC as u64),
@@ -251,6 +256,7 @@ impl Duration {
     ///
     /// [`subsec_nanos`]: #method.subsec_nanos
     #[stable(feature = "duration", since = "1.3.0")]
+    #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "duration", since = "1.32.0"))]
     #[inline]
     pub const fn as_secs(&self) -> u64 {
         self.secs
@@ -272,6 +278,7 @@ impl Duration {
     /// assert_eq!(duration.subsec_millis(), 432);
     /// ```
     #[stable(feature = "duration_extras", since = "1.27.0")]
+    #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "duration_extras", since = "1.32.0"))]
     #[inline]
     pub const fn subsec_millis(&self) -> u32 {
         self.nanos / NANOS_PER_MILLI
@@ -293,6 +300,7 @@ impl Duration {
     /// assert_eq!(duration.subsec_micros(), 234_567);
     /// ```
     #[stable(feature = "duration_extras", since = "1.27.0")]
+    #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "duration_extras", since = "1.32.0"))]
     #[inline]
     pub const fn subsec_micros(&self) -> u32 {
         self.nanos / NANOS_PER_MICRO
@@ -314,6 +322,7 @@ impl Duration {
     /// assert_eq!(duration.subsec_nanos(), 10_000_000);
     /// ```
     #[stable(feature = "duration", since = "1.3.0")]
+    #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "duration", since = "1.32.0"))]
     #[inline]
     pub const fn subsec_nanos(&self) -> u32 {
         self.nanos
@@ -330,6 +339,7 @@ impl Duration {
     /// assert_eq!(duration.as_millis(), 5730);
     /// ```
     #[stable(feature = "duration_as_u128", since = "1.33.0")]
+    #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "duration_as_u128", since = "1.33.0"))]
     #[inline]
     pub const fn as_millis(&self) -> u128 {
         self.secs as u128 * MILLIS_PER_SEC as u128 + (self.nanos / NANOS_PER_MILLI) as u128
@@ -346,6 +356,7 @@ impl Duration {
     /// assert_eq!(duration.as_micros(), 5730023);
     /// ```
     #[stable(feature = "duration_as_u128", since = "1.33.0")]
+    #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "duration_as_u128", since = "1.33.0"))]
     #[inline]
     pub const fn as_micros(&self) -> u128 {
         self.secs as u128 * MICROS_PER_SEC as u128 + (self.nanos / NANOS_PER_MICRO) as u128
@@ -362,6 +373,7 @@ impl Duration {
     /// assert_eq!(duration.as_nanos(), 5730023852);
     /// ```
     #[stable(feature = "duration_as_u128", since = "1.33.0")]
+    #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "duration_as_u128", since = "1.33.0"))]
     #[inline]
     pub const fn as_nanos(&self) -> u128 {
         self.secs as u128 * NANOS_PER_SEC as u128 + self.nanos as u128
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index 54aafe2114d..51756084f24 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -19,7 +19,7 @@ use syntax_pos::{Span, MultiSpan};
 use syntax::ast::{Attribute, CRATE_NODE_ID};
 use syntax::errors::Applicability;
 use syntax::feature_gate::{feature_err, feature_err_issue};
-use syntax::attr::{self, Stability, Deprecation, RustcDeprecation};
+use syntax::attr::{self, Stability, Deprecation, RustcDeprecation, ConstStability};
 use crate::ty::{self, TyCtxt};
 use crate::util::nodemap::{FxHashSet, FxHashMap};
 
@@ -91,6 +91,7 @@ pub struct Index<'tcx> {
     /// This is mostly a cache, except the stabilities of local items
     /// are filled by the annotator.
     stab_map: FxHashMap<HirId, &'tcx Stability>,
+    const_stab_map: FxHashMap<HirId, &'tcx ConstStability>,
     depr_map: FxHashMap<HirId, DeprecationEntry>,
 
     /// Maps for each crate whether it is part of the staged API.
@@ -123,8 +124,14 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
                 self.tcx.sess.span_err(item_sp, "`#[deprecated]` cannot be used in staged API; \
                                                  use `#[rustc_deprecated]` instead");
             }
-            if let Some(mut stab) = attr::find_stability(&self.tcx.sess.parse_sess,
-                                                         attrs, item_sp) {
+            let (stab, const_stab) = attr::find_stability(
+                &self.tcx.sess.parse_sess, attrs, item_sp,
+            );
+            if let Some(const_stab) = const_stab {
+                let const_stab = self.tcx.intern_const_stability(const_stab);
+                self.index.const_stab_map.insert(hir_id, const_stab);
+            }
+            if let Some(mut stab) = stab {
                 // Error if prohibited, or can't inherit anything from a container.
                 if kind == AnnotationKind::Prohibited ||
                    (kind == AnnotationKind::Container &&
@@ -189,9 +196,15 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
             }
         } else {
             // Emit errors for non-staged-api crates.
+            let unstable_attrs = [
+                sym::unstable, sym::stable,
+                sym::rustc_deprecated,
+                sym::rustc_const_unstable,
+                sym::rustc_const_stable,
+            ];
             for attr in attrs {
                 let name = attr.name_or_empty();
-                if [sym::unstable, sym::stable, sym::rustc_deprecated].contains(&name) {
+                if unstable_attrs.contains(&name) {
                     attr::mark_used(attr);
                     struct_span_err!(
                         self.tcx.sess,
@@ -399,6 +412,7 @@ impl<'tcx> Index<'tcx> {
         let mut index = Index {
             staged_api,
             stab_map: Default::default(),
+            const_stab_map: Default::default(),
             depr_map: Default::default(),
             active_features: Default::default(),
         };
@@ -440,9 +454,6 @@ impl<'tcx> Index<'tcx> {
                     },
                     feature: sym::rustc_private,
                     rustc_depr: None,
-                    const_stability: None,
-                    promotable: false,
-                    allow_const_fn_ptr: false,
                 });
                 annotator.parent_stab = Some(stability);
             }
@@ -460,6 +471,10 @@ impl<'tcx> Index<'tcx> {
         self.stab_map.get(&id).cloned()
     }
 
+    pub fn local_const_stability(&self, id: HirId) -> Option<&'tcx ConstStability> {
+        self.const_stab_map.get(&id).cloned()
+    }
+
     pub fn local_deprecation_entry(&self, id: HirId) -> Option<DeprecationEntry> {
         self.depr_map.get(&id).cloned()
     }
diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs
index 538b13c79ce..cc02165f605 100644
--- a/src/librustc/query/mod.rs
+++ b/src/librustc/query/mod.rs
@@ -533,6 +533,7 @@ rustc_queries! {
             eval_always
         }
         query lookup_stability(_: DefId) -> Option<&'tcx attr::Stability> {}
+        query lookup_const_stability(_: DefId) -> Option<&'tcx attr::ConstStability> {}
         query lookup_deprecation_entry(_: DefId) -> Option<DeprecationEntry> {}
         query item_attrs(_: DefId) -> Lrc<[ast::Attribute]> {}
     }
diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs
index 268015a5624..897a3678c40 100644
--- a/src/librustc/ty/constness.rs
+++ b/src/librustc/ty/constness.rs
@@ -30,7 +30,12 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
     pub fn is_unstable_const_fn(self, def_id: DefId) -> Option<Symbol> {
         if self.is_const_fn_raw(def_id) {
-            self.lookup_stability(def_id)?.const_stability
+            let const_stab = self.lookup_const_stability(def_id)?;
+            if const_stab.level.is_unstable() {
+                Some(const_stab.feature)
+            } else {
+                None
+            }
         } else {
             None
         }
@@ -83,15 +88,36 @@ impl<'tcx> TyCtxt<'tcx> {
         }
 
         if self.features().staged_api {
-            // in order for a libstd function to be considered min_const_fn
-            // it needs to be stable and have no `rustc_const_unstable` attribute
-            match self.lookup_stability(def_id) {
-                // stable functions with unstable const fn aren't `min_const_fn`
-                Some(&attr::Stability { const_stability: Some(_), .. }) => false,
-                // unstable functions don't need to conform
-                Some(&attr::Stability { ref level, .. }) if level.is_unstable() => false,
-                // everything else needs to conform, because it would be callable from
-                // other `min_const_fn` functions
+            // In order for a libstd function to be considered min_const_fn
+            // it needs to be stable and have no `rustc_const_unstable` attribute.
+            match self.lookup_const_stability(def_id) {
+                // `rustc_const_unstable` functions don't need to conform.
+                Some(&attr::ConstStability { ref level, .. }) if level.is_unstable() => false,
+                None => if let Some(stab) = self.lookup_stability(def_id) {
+                    if stab.level.is_stable() {
+                        self.sess.span_err(
+                            self.def_span(def_id),
+                            "stable const functions must have either `rustc_const_stable` or \
+                            `rustc_const_unstable` attribute",
+                        );
+                        // While we errored above, because we don't know if we need to conform, we
+                        // err on the "safe" side and require min_const_fn.
+                        true
+                    } else {
+                        // Unstable functions need not conform to min_const_fn.
+                        false
+                    }
+                } else {
+                    // Internal functions are forced to conform to min_const_fn.
+                    // Annotate the internal function with a const stability attribute if
+                    // you need to use unstable features.
+                    // Note: this is an arbitrary choice that does not affect stability or const
+                    // safety or anything, it just changes whether we need to annotate some
+                    // internal functions with `rustc_const_stable` or with `rustc_const_unstable`
+                    true
+                },
+                // Everything else needs to conform, because it would be callable from
+                // other `min_const_fn` functions.
                 _ => true,
             }
         } else {
@@ -188,7 +214,7 @@ pub fn provide(providers: &mut Providers<'_>) {
     }
 
     fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-        tcx.is_const_fn(def_id) && match tcx.lookup_stability(def_id) {
+        tcx.is_const_fn(def_id) && match tcx.lookup_const_stability(def_id) {
             Some(stab) => {
                 if cfg!(debug_assertions) && stab.promotable {
                     let sig = tcx.fn_sig(def_id);
@@ -207,7 +233,7 @@ pub fn provide(providers: &mut Providers<'_>) {
 
     fn const_fn_is_allowed_fn_ptr(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
         tcx.is_const_fn(def_id) &&
-            tcx.lookup_stability(def_id)
+            tcx.lookup_const_stability(def_id)
                 .map(|stab| stab.allow_const_fn_ptr).unwrap_or(false)
     }
 
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index f7e422b0403..595ea40b2ff 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -1066,8 +1066,12 @@ pub struct GlobalCtxt<'tcx> {
     /// Data layout specification for the current target.
     pub data_layout: TargetDataLayout,
 
+    /// `#[stable]` and `#[unstable]` attributes
     stability_interner: ShardedHashMap<&'tcx attr::Stability, ()>,
 
+    /// `#[rustc_const_stable]` and `#[rustc_const_unstable]` attributes
+    const_stability_interner: ShardedHashMap<&'tcx attr::ConstStability, ()>,
+
     /// Stores the value of constants (and deduplicates the actual memory)
     allocation_interner: ShardedHashMap<&'tcx Allocation, ()>,
 
@@ -1129,6 +1133,12 @@ impl<'tcx> TyCtxt<'tcx> {
         })
     }
 
+    pub fn intern_const_stability(self, stab: attr::ConstStability) -> &'tcx attr::ConstStability {
+        self.const_stability_interner.intern(stab, |stab| {
+            self.arena.alloc(stab)
+        })
+    }
+
     pub fn intern_layout(self, layout: LayoutDetails) -> &'tcx LayoutDetails {
         self.layout_interner.intern(layout, |layout| {
             self.arena.alloc(layout)
@@ -1269,6 +1279,7 @@ impl<'tcx> TyCtxt<'tcx> {
             data_layout,
             layout_interner: Default::default(),
             stability_interner: Default::default(),
+            const_stability_interner: Default::default(),
             allocation_interner: Default::default(),
             alloc_map: Lock::new(interpret::AllocMap::new()),
             output_filenames: Arc::new(output_filenames.clone()),
@@ -2058,6 +2069,7 @@ impl<'tcx> TyCtxt<'tcx> {
         println!("InternalSubsts interner: #{}", self.interners.substs.len());
         println!("Region interner: #{}", self.interners.region.len());
         println!("Stability interner: #{}", self.stability_interner.len());
+        println!("Const Stability interner: #{}", self.const_stability_interner.len());
         println!("Allocation interner: #{}", self.allocation_interner.len());
         println!("Layout interner: #{}", self.layout_interner.len());
     }
@@ -2992,6 +3004,11 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
         let id = tcx.hir().definitions().def_index_to_hir_id(id.index);
         tcx.stability().local_stability(id)
     };
+    providers.lookup_const_stability = |tcx, id| {
+        assert_eq!(id.krate, LOCAL_CRATE);
+        let id = tcx.hir().definitions().def_index_to_hir_id(id.index);
+        tcx.stability().local_const_stability(id)
+    };
     providers.lookup_deprecation_entry = |tcx, id| {
         assert_eq!(id.krate, LOCAL_CRATE);
         let id = tcx.hir().definitions().def_index_to_hir_id(id.index);
diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs
index 363621b3ca4..98213b890f9 100644
--- a/src/librustc_feature/active.rs
+++ b/src/librustc_feature/active.rs
@@ -111,10 +111,6 @@ declare_features! (
     /// macros disappear).
     (active, allow_internal_unsafe, "1.0.0", None, None),
 
-    /// Allows using `#[rustc_const_unstable(feature = "foo", ..)]` which
-    /// lets a function to be `const` when opted into with `#![feature(foo)]`.
-    (active, rustc_const_unstable, "1.0.0", None, None),
-
     /// no-tracking-issue-end
 
     /// Allows using `#[link_name="llvm.*"]`.
diff --git a/src/librustc_feature/builtin_attrs.rs b/src/librustc_feature/builtin_attrs.rs
index 4fa0198d871..0a4fb8a224e 100644
--- a/src/librustc_feature/builtin_attrs.rs
+++ b/src/librustc_feature/builtin_attrs.rs
@@ -344,10 +344,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         unstable, Whitelisted,
         template!(List: r#"feature = "name", reason = "...", issue = "N""#),
     ),
-    gated!(
-        rustc_const_unstable, Normal, template!(List: r#"feature = "name""#),
-        "the `#[rustc_const_unstable]` attribute is an internal feature",
-    ),
+    // FIXME(#14407)
+    ungated!(rustc_const_unstable, Whitelisted, template!(List: r#"feature = "name""#)),
+    // FIXME(#14407)
+    ungated!(rustc_const_stable, Whitelisted, template!(List: r#"feature = "name""#)),
     gated!(
         allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."),
         "allow_internal_unstable side-steps feature gating and stability checks",
diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs
index 0107a22772f..a1f95e35cbe 100644
--- a/src/librustc_metadata/rmeta/decoder.rs
+++ b/src/librustc_metadata/rmeta/decoder.rs
@@ -852,6 +852,10 @@ impl<'a, 'tcx> CrateMetadata {
         }
     }
 
+    fn get_const_stability(&self, id: DefIndex) -> Option<attr::ConstStability> {
+        self.root.per_def.const_stability.get(self, id).map(|stab| stab.decode(self))
+    }
+
     fn get_deprecation(&self, id: DefIndex) -> Option<attr::Deprecation> {
         self.root.per_def.deprecation.get(self, id)
             .filter(|_| !self.is_proc_macro(id))
diff --git a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs
index 13db9a6fef9..4a6b25930c8 100644
--- a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs
+++ b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs
@@ -134,6 +134,9 @@ provide! { <'tcx> tcx, def_id, other, cdata,
     lookup_stability => {
         cdata.get_stability(def_id.index).map(|s| tcx.intern_stability(s))
     }
+    lookup_const_stability => {
+        cdata.get_const_stability(def_id.index).map(|s| tcx.intern_const_stability(s))
+    }
     lookup_deprecation_entry => {
         cdata.get_deprecation(def_id.index).map(DeprecationEntry::external)
     }
diff --git a/src/librustc_metadata/rmeta/encoder.rs b/src/librustc_metadata/rmeta/encoder.rs
index fb70e10c84f..c1562a77342 100644
--- a/src/librustc_metadata/rmeta/encoder.rs
+++ b/src/librustc_metadata/rmeta/encoder.rs
@@ -866,6 +866,7 @@ impl EncodeContext<'tcx> {
         record!(self.per_def.span[def_id] <- ast_item.span);
         record!(self.per_def.attributes[def_id] <- &ast_item.attrs);
         self.encode_stability(def_id);
+        self.encode_const_stability(def_id);
         self.encode_deprecation(def_id);
         match trait_item.kind {
             ty::AssocKind::Const |
@@ -946,6 +947,7 @@ impl EncodeContext<'tcx> {
         record!(self.per_def.span[def_id] <- ast_item.span);
         record!(self.per_def.attributes[def_id] <- &ast_item.attrs);
         self.encode_stability(def_id);
+        self.encode_const_stability(def_id);
         self.encode_deprecation(def_id);
         self.encode_item_type(def_id);
         if impl_item.kind == ty::AssocKind::Method {
@@ -1025,6 +1027,13 @@ impl EncodeContext<'tcx> {
         }
     }
 
+    fn encode_const_stability(&mut self, def_id: DefId) {
+        debug!("EncodeContext::encode_const_stability({:?})", def_id);
+        if let Some(stab) = self.tcx.lookup_const_stability(def_id) {
+            record!(self.per_def.const_stability[def_id] <- stab)
+        }
+    }
+
     fn encode_deprecation(&mut self, def_id: DefId) {
         debug!("EncodeContext::encode_deprecation({:?})", def_id);
         if let Some(depr) = self.tcx.lookup_deprecation(def_id) {
@@ -1186,6 +1195,7 @@ impl EncodeContext<'tcx> {
             _ => {}
         }
         self.encode_stability(def_id);
+        self.encode_const_stability(def_id);
         self.encode_deprecation(def_id);
         match item.kind {
             hir::ItemKind::Static(..) |
@@ -1545,6 +1555,7 @@ impl EncodeContext<'tcx> {
         record!(self.per_def.span[def_id] <- nitem.span);
         record!(self.per_def.attributes[def_id] <- &nitem.attrs);
         self.encode_stability(def_id);
+        self.encode_const_stability(def_id);
         self.encode_deprecation(def_id);
         self.encode_item_type(def_id);
         if let hir::ForeignItemKind::Fn(..) = nitem.kind {
diff --git a/src/librustc_metadata/rmeta/mod.rs b/src/librustc_metadata/rmeta/mod.rs
index 5abae429373..e13edc2d621 100644
--- a/src/librustc_metadata/rmeta/mod.rs
+++ b/src/librustc_metadata/rmeta/mod.rs
@@ -261,6 +261,7 @@ define_per_def_tables! {
     attributes: Table<DefIndex, Lazy<[ast::Attribute]>>,
     children: Table<DefIndex, Lazy<[DefIndex]>>,
     stability: Table<DefIndex, Lazy<attr::Stability>>,
+    const_stability: Table<DefIndex, Lazy<attr::ConstStability>>,
     deprecation: Table<DefIndex, Lazy<attr::Deprecation>>,
     ty: Table<DefIndex, Lazy!(Ty<'tcx>)>,
     fn_sig: Table<DefIndex, Lazy!(ty::PolyFnSig<'tcx>)>,
diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs
index 6dcda986310..14ca0423d8b 100644
--- a/src/libstd/ffi/c_str.rs
+++ b/src/libstd/ffi/c_str.rs
@@ -1065,7 +1065,8 @@ impl CStr {
     /// ```
     #[inline]
     #[stable(feature = "cstr_from_bytes", since = "1.10.0")]
-    #[rustc_const_unstable(feature = "const_cstr_unchecked")]
+    #[cfg_attr(bootstrap, rustc_const_unstable(feature = "const_cstr_unchecked"))]
+    #[cfg_attr(not(bootstrap), rustc_const_unstable(feature = "const_cstr_unchecked", issue = "0"))]
     pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
         &*(bytes as *const [u8] as *const CStr)
     }
@@ -1119,6 +1120,7 @@ impl CStr {
     /// [`CString`]: struct.CString.html
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "const_str_as_ptr", since = "1.32.0"))]
     pub const fn as_ptr(&self) -> *const c_char {
         self.inner.as_ptr()
     }
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 1dbb0c6ec83..8198ae73a31 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -293,7 +293,7 @@
 #![feature(raw)]
 #![feature(renamed_spin_loop)]
 #![feature(rustc_attrs)]
-#![feature(rustc_const_unstable)]
+#![cfg_attr(bootstrap, feature(rustc_const_unstable))]
 #![feature(rustc_private)]
 #![feature(shrink_to)]
 #![feature(slice_concat_ext)]
diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs
index e51a9b62449..7d69f8f4b8d 100644
--- a/src/libstd/net/ip.rs
+++ b/src/libstd/net/ip.rs
@@ -319,6 +319,7 @@ impl Ipv4Addr {
     /// let addr = Ipv4Addr::new(127, 0, 0, 1);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "const_ipv4", since = "1.32.0"))]
     pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
         // FIXME: should just be u32::from_be_bytes([a, b, c, d]),
         // once that method is no longer rustc_const_unstable
@@ -406,6 +407,7 @@ impl Ipv4Addr {
     /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_unspecified(), false);
     /// ```
     #[stable(feature = "ip_shared", since = "1.12.0")]
+    #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "const_ipv4", since = "1.32.0"))]
     pub const fn is_unspecified(&self) -> bool {
         self.inner.s_addr == 0
     }
@@ -1015,6 +1017,7 @@ impl Ipv6Addr {
     /// let addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "const_ipv6", since = "1.32.0"))]
     pub const fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16,
                      g: u16, h: u16) -> Ipv6Addr {
         Ipv6Addr {
@@ -1480,6 +1483,7 @@ impl Ipv6Addr {
     ///            [255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
     /// ```
     #[stable(feature = "ipv6_to_octets", since = "1.12.0")]
+    #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "const_ipv6", since = "1.32.0"))]
     pub const fn octets(&self) -> [u8; 16] {
         self.inner.s6_addr
     }
diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs
index e8e395247f9..d8df09071cd 100644
--- a/src/libstd/sync/once.rs
+++ b/src/libstd/sync/once.rs
@@ -188,6 +188,7 @@ struct WaiterQueue<'a> {
 impl Once {
     /// Creates a new `Once` value.
     #[stable(feature = "once_new", since = "1.2.0")]
+    #[cfg_attr(not(bootstrap), rustc_const_stable(feature = "const_once_new", since = "1.32.0"))]
     pub const fn new() -> Once {
         Once { state_and_queue: AtomicUsize::new(INCOMPLETE), _marker: marker::PhantomData }
     }
diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs
index 3c10f27b60a..a37b27f67bc 100644
--- a/src/libsyntax/attr/builtin.rs
+++ b/src/libsyntax/attr/builtin.rs
@@ -120,17 +120,21 @@ pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Op
     })
 }
 
-/// Represents the #[stable], #[unstable], #[rustc_{deprecated,const_unstable}] attributes.
+/// Represents the #[stable], #[unstable], #[rustc_deprecated] attributes.
 #[derive(RustcEncodable, RustcDecodable, Copy, Clone, Debug,
          PartialEq, Eq, Hash, HashStable_Generic)]
 pub struct Stability {
     pub level: StabilityLevel,
     pub feature: Symbol,
     pub rustc_depr: Option<RustcDeprecation>,
-    /// `None` means the function is stable but needs to be a stable const fn, too
-    /// `Some` contains the feature gate required to be able to use the function
-    /// as const fn
-    pub const_stability: Option<Symbol>,
+}
+
+/// Represents the #[rustc_const_unstable] and #[rustc_const_stable] attributes.
+#[derive(RustcEncodable, RustcDecodable, Copy, Clone, Debug,
+         PartialEq, Eq, Hash, HashStable_Generic)]
+pub struct ConstStability {
+    pub level: StabilityLevel,
+    pub feature: Symbol,
     /// whether the function has a `#[rustc_promotable]` attribute
     pub promotable: bool,
     /// whether the function has a `#[rustc_allow_const_fn_ptr]` attribute
@@ -186,21 +190,21 @@ pub fn contains_feature_attr(attrs: &[Attribute], feature_name: Symbol) -> bool
 /// Collects stability info from all stability attributes in `attrs`.
 /// Returns `None` if no stability attributes are found.
 pub fn find_stability(sess: &ParseSess, attrs: &[Attribute],
-                      item_sp: Span) -> Option<Stability> {
+                      item_sp: Span) -> (Option<Stability>, Option<ConstStability>) {
     find_stability_generic(sess, attrs.iter(), item_sp)
 }
 
 fn find_stability_generic<'a, I>(sess: &ParseSess,
                                  attrs_iter: I,
                                  item_sp: Span)
-                                 -> Option<Stability>
+                                 -> (Option<Stability>, Option<ConstStability>)
     where I: Iterator<Item = &'a Attribute>
 {
     use StabilityLevel::*;
 
     let mut stab: Option<Stability> = None;
     let mut rustc_depr: Option<RustcDeprecation> = None;
-    let mut rustc_const_unstable: Option<Symbol> = None;
+    let mut const_stab: Option<ConstStability> = None;
     let mut promotable = false;
     let mut allow_const_fn_ptr = false;
     let diagnostic = &sess.span_diagnostic;
@@ -209,6 +213,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
         if ![
             sym::rustc_deprecated,
             sym::rustc_const_unstable,
+            sym::rustc_const_stable,
             sym::unstable,
             sym::stable,
             sym::rustc_promotable,
@@ -287,7 +292,8 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
                 }
             }
 
-            match meta.name_or_empty() {
+            let meta_name = meta.name_or_empty();
+            match meta_name {
                 sym::rustc_deprecated => {
                     if rustc_depr.is_some() {
                         span_err!(diagnostic, item_sp, E0540,
@@ -315,23 +321,12 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
                         }
                     }
                 }
-                sym::rustc_const_unstable => {
-                    if rustc_const_unstable.is_some() {
-                        span_err!(diagnostic, item_sp, E0553,
-                                  "multiple rustc_const_unstable attributes");
-                        continue 'outer
-                    }
-
-                    get_meta!(feature);
-                    if let Some(feature) = feature {
-                        rustc_const_unstable = Some(feature);
-                    } else {
-                        span_err!(diagnostic, attr.span, E0629, "missing 'feature'");
-                        continue
-                    }
-                }
+                sym::rustc_const_unstable |
                 sym::unstable => {
-                    if stab.is_some() {
+                    if meta_name == sym::unstable && stab.is_some() {
+                        handle_errors(sess, attr.span, AttrError::MultipleStabilityLevels);
+                        break
+                    } else if meta_name == sym::rustc_const_unstable && const_stab.is_some() {
                         handle_errors(sess, attr.span, AttrError::MultipleStabilityLevels);
                         break
                     }
@@ -398,18 +393,25 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
                                     }
                                 }
                             };
-                            stab = Some(Stability {
-                                level: Unstable {
-                                    reason,
-                                    issue,
-                                    is_soft,
-                                },
-                                feature,
-                                rustc_depr: None,
-                                const_stability: None,
-                                promotable: false,
-                                allow_const_fn_ptr: false,
-                            })
+                            let level = Unstable {
+                                reason,
+                                issue,
+                                is_soft,
+                            };
+                            if sym::unstable == meta_name {
+                                stab = Some(Stability {
+                                    level,
+                                    feature,
+                                    rustc_depr: None,
+                                });
+                            } else {
+                                const_stab = Some(ConstStability {
+                                    level,
+                                    feature,
+                                    promotable: false,
+                                    allow_const_fn_ptr: false,
+                                });
+                            }
                         }
                         (None, _, _) => {
                             handle_errors(sess, attr.span, AttrError::MissingFeature);
@@ -421,8 +423,12 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
                         }
                     }
                 }
+                sym::rustc_const_stable |
                 sym::stable => {
-                    if stab.is_some() {
+                    if meta_name == sym::stable && stab.is_some() {
+                        handle_errors(sess, attr.span, AttrError::MultipleStabilityLevels);
+                        break
+                    } else if meta_name == sym::rustc_const_stable &&const_stab.is_some() {
                         handle_errors(sess, attr.span, AttrError::MultipleStabilityLevels);
                         break
                     }
@@ -464,16 +470,21 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
 
                     match (feature, since) {
                         (Some(feature), Some(since)) => {
-                            stab = Some(Stability {
-                                level: Stable {
-                                    since,
-                                },
-                                feature,
-                                rustc_depr: None,
-                                const_stability: None,
-                                promotable: false,
-                                allow_const_fn_ptr: false,
-                            })
+                            let level =  Stable { since };
+                            if sym::stable == meta_name {
+                                stab = Some(Stability {
+                                    level,
+                                    feature,
+                                    rustc_depr: None,
+                                });
+                            } else {
+                                const_stab = Some(ConstStability {
+                                    level,
+                                    feature,
+                                    promotable: false,
+                                    allow_const_fn_ptr: false,
+                                });
+                            }
                         }
                         (None, _) => {
                             handle_errors(sess, attr.span, AttrError::MissingFeature);
@@ -502,29 +513,19 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
     }
 
     // Merge the const-unstable info into the stability info
-    if let Some(feature) = rustc_const_unstable {
-        if let Some(ref mut stab) = stab {
-            stab.const_stability = Some(feature);
-        } else {
-            span_err!(diagnostic, item_sp, E0630,
-                      "rustc_const_unstable attribute must be paired with \
-                       either stable or unstable attribute");
-        }
-    }
-
-    // Merge the const-unstable info into the stability info
     if promotable || allow_const_fn_ptr {
-        if let Some(ref mut stab) = stab {
+        if let Some(ref mut stab) = const_stab {
             stab.promotable = promotable;
             stab.allow_const_fn_ptr = allow_const_fn_ptr;
         } else {
             span_err!(diagnostic, item_sp, E0717,
                       "rustc_promotable and rustc_allow_const_fn_ptr attributes \
-                      must be paired with either stable or unstable attribute");
+                      must be paired with either a rustc_const_unstable or a rustc_const_stable \
+                      attribute");
         }
     }
 
-    stab
+    (stab, const_stab)
 }
 
 pub fn find_crate_name(attrs: &[Attribute]) -> Option<Symbol> {
diff --git a/src/libsyntax_expand/base.rs b/src/libsyntax_expand/base.rs
index a4449ca5b1d..72c0b3fde02 100644
--- a/src/libsyntax_expand/base.rs
+++ b/src/libsyntax_expand/base.rs
@@ -775,6 +775,10 @@ impl SyntaxExtension {
         }
 
         let is_builtin = attr::contains_name(attrs, sym::rustc_builtin_macro);
+        let (stability, const_stability) = attr::find_stability(&sess, attrs, span);
+        if const_stability.is_some() {
+            sess.span_diagnostic.span_err(span, "macros cannot have const stability attributes");
+        }
 
         SyntaxExtension {
             kind,
@@ -782,7 +786,7 @@ impl SyntaxExtension {
             allow_internal_unstable,
             allow_internal_unsafe: attr::contains_name(attrs, sym::allow_internal_unsafe),
             local_inner_macros,
-            stability: attr::find_stability(&sess, attrs, span),
+            stability,
             deprecation: attr::find_deprecation(&sess, attrs, span),
             helper_attrs,
             edition,
diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs
index 92de56bd09a..c7e4182de6b 100644
--- a/src/libsyntax_pos/symbol.rs
+++ b/src/libsyntax_pos/symbol.rs
@@ -605,6 +605,7 @@ symbols! {
         rustc_builtin_macro,
         rustc_clean,
         rustc_const_unstable,
+        rustc_const_stable,
         rustc_conversion_suggestion,
         rustc_def_path,
         rustc_deprecated,
diff --git a/src/test/rustdoc/const-display.rs b/src/test/rustdoc/const-display.rs
index 9df0368c40d..bc7ad04b6a2 100644
--- a/src/test/rustdoc/const-display.rs
+++ b/src/test/rustdoc/const-display.rs
@@ -4,12 +4,12 @@
             reason = "who ever let humans program computers, we're apparently really bad at it",
             issue = "0")]
 
-#![feature(rustc_const_unstable, const_fn, foo, foo2)]
+#![feature(foo, foo2)]
 #![feature(staged_api)]
 
 // @has 'foo/fn.foo.html' '//pre' 'pub unsafe fn foo() -> u32'
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature="foo")]
+#[rustc_const_unstable(feature="foo", issue = "0")]
 pub const unsafe fn foo() -> u32 { 42 }
 
 // @has 'foo/fn.foo2.html' '//pre' 'pub fn foo2() -> u32'
@@ -18,6 +18,7 @@ pub const fn foo2() -> u32 { 42 }
 
 // @has 'foo/fn.bar2.html' '//pre' 'pub const fn bar2() -> u32'
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 pub const fn bar2() -> u32 { 42 }
 
 // @has 'foo/fn.foo2_gated.html' '//pre' 'pub unsafe fn foo2_gated() -> u32'
@@ -26,6 +27,7 @@ pub const unsafe fn foo2_gated() -> u32 { 42 }
 
 // @has 'foo/fn.bar2_gated.html' '//pre' 'pub const unsafe fn bar2_gated() -> u32'
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 pub const unsafe fn bar2_gated() -> u32 { 42 }
 
 // @has 'foo/fn.bar_not_gated.html' '//pre' 'pub unsafe fn bar_not_gated() -> u32'
diff --git a/src/test/ui/consts/auxiliary/promotable_const_fn_lib.rs b/src/test/ui/consts/auxiliary/promotable_const_fn_lib.rs
index e54cbb09804..b1d5440b41a 100644
--- a/src/test/ui/consts/auxiliary/promotable_const_fn_lib.rs
+++ b/src/test/ui/consts/auxiliary/promotable_const_fn_lib.rs
@@ -7,6 +7,7 @@
 
 #[rustc_promotable]
 #[stable(since="1.0.0", feature = "mep")]
+#[rustc_const_stable(since="1.0.0", feature = "mep")]
 #[inline]
 pub const fn foo() -> usize { 22 }
 
@@ -15,6 +16,7 @@ pub struct Foo(usize);
 
 impl Foo {
     #[stable(since="1.0.0", feature = "mep")]
+    #[rustc_const_stable(feature = "mep", since = "1.0.0")]
     #[inline]
     #[rustc_promotable]
     pub const fn foo() -> usize { 22 }
diff --git a/src/test/ui/consts/const-eval/auxiliary/stability.rs b/src/test/ui/consts/const-eval/auxiliary/stability.rs
index 5551d35bcc8..830db55207f 100644
--- a/src/test/ui/consts/const-eval/auxiliary/stability.rs
+++ b/src/test/ui/consts/const-eval/auxiliary/stability.rs
@@ -3,9 +3,9 @@
 #![crate_type="rlib"]
 #![stable(feature = "rust1", since = "1.0.0")]
 
-#![feature(rustc_const_unstable, const_fn)]
+#![feature(const_fn)]
 #![feature(staged_api)]
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature="foo")]
+#[rustc_const_unstable(feature="foo", issue = "0")]
 pub const fn foo() -> u32 { 42 }
diff --git a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.rs b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.rs
index 90028690990..c4b89b50bc4 100644
--- a/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.rs
+++ b/src/test/ui/consts/const-eval/dont_promote_unstable_const_fn.rs
@@ -3,11 +3,11 @@
             we're apparently really bad at it",
             issue = "0")]
 
-#![feature(rustc_const_unstable, const_fn)]
+#![feature(const_fn)]
 #![feature(staged_api)]
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature="foo")]
+#[rustc_const_unstable(feature="foo", issue = "0")]
 const fn foo() -> u32 { 42 }
 
 fn meh() -> u32 { 42 }
diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs
index 3992607c387..937aae1a8e3 100644
--- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs
+++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs
@@ -1,10 +1,12 @@
 #![feature(rustc_attrs, staged_api)]
 
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(since="1.0.0", feature = "mep")]
 const fn error(_: fn()) {} //~ ERROR function pointers in const fn are unstable
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_allow_const_fn_ptr]
+#[rustc_const_stable(since="1.0.0", feature = "mep")]
 const fn compiles(_: fn()) {}
 
 fn main() {}
diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr
index 6228b012dde..0ede4229ade 100644
--- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr
+++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr
@@ -1,5 +1,5 @@
 error[E0723]: function pointers in const fn are unstable
-  --> $DIR/allow_const_fn_ptr.rs:4:16
+  --> $DIR/allow_const_fn_ptr.rs:5:16
    |
 LL | const fn error(_: fn()) {}
    |                ^
diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs
index 1d8b95ab1a2..7aa9bd7e2dc 100644
--- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs
+++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs
@@ -5,6 +5,7 @@
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_allow_const_fn_ptr]
+#[rustc_const_stable(since="1.0.0", feature = "mep")]
 const fn takes_fn_ptr(_: fn()) {}
 
 const FN: fn() = || ();
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs
index 759d9ab6a40..97e467aece2 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs
@@ -3,14 +3,15 @@
             we're apparently really bad at it",
             issue = "0")]
 
-#![feature(rustc_const_unstable, const_fn, foo, foo2)]
+#![feature(const_fn, foo, foo2)]
 #![feature(staged_api)]
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature="foo")]
+#[rustc_const_unstable(feature="foo", issue = "0")]
 const fn foo() -> u32 { 42 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
 const fn bar() -> u32 { foo() } //~ ERROR can only call other `const fn`
 
@@ -18,10 +19,12 @@ const fn bar() -> u32 { foo() } //~ ERROR can only call other `const fn`
 const fn foo2() -> u32 { 42 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
 const fn bar2() -> u32 { foo2() } //~ ERROR can only call other `const fn`
 
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // conformity is required, even with `const_fn` feature gate
 const fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` operations
 
@@ -30,6 +33,7 @@ const fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `
 const fn foo2_gated() -> u32 { 42 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
 const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `const fn`
 
diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr
index 0af5bdca815..1da9b41aa59 100644
--- a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr
@@ -1,5 +1,5 @@
 error[E0723]: can only call other `const fn` within a `const fn`, but `const foo` is not stable as `const fn`
-  --> $DIR/min_const_fn_libstd_stability.rs:15:25
+  --> $DIR/min_const_fn_libstd_stability.rs:16:25
    |
 LL | const fn bar() -> u32 { foo() }
    |                         ^^^^^
@@ -8,7 +8,7 @@ LL | const fn bar() -> u32 { foo() }
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2` is not stable as `const fn`
-  --> $DIR/min_const_fn_libstd_stability.rs:22:26
+  --> $DIR/min_const_fn_libstd_stability.rs:24:26
    |
 LL | const fn bar2() -> u32 { foo2() }
    |                          ^^^^^^
@@ -17,7 +17,7 @@ LL | const fn bar2() -> u32 { foo2() }
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: only int, `bool` and `char` operations are stable in const fn
-  --> $DIR/min_const_fn_libstd_stability.rs:26:26
+  --> $DIR/min_const_fn_libstd_stability.rs:29:26
    |
 LL | const fn bar3() -> u32 { (5f32 + 6f32) as u32 }
    |                          ^^^^^^^^^^^^^
@@ -26,7 +26,7 @@ LL | const fn bar3() -> u32 { (5f32 + 6f32) as u32 }
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2_gated` is not stable as `const fn`
-  --> $DIR/min_const_fn_libstd_stability.rs:34:32
+  --> $DIR/min_const_fn_libstd_stability.rs:38:32
    |
 LL | const fn bar2_gated() -> u32 { foo2_gated() }
    |                                ^^^^^^^^^^^^
diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs
index 64057b012b8..102b3801441 100644
--- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs
@@ -3,14 +3,15 @@
             we're apparently really bad at it",
             issue = "0")]
 
-#![feature(rustc_const_unstable, const_fn, foo, foo2)]
+#![feature(const_fn, foo, foo2)]
 #![feature(staged_api)]
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature="foo")]
+#[rustc_const_unstable(feature="foo", issue = "0")]
 const unsafe fn foo() -> u32 { 42 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
 const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR can only call other `const fn`
 
@@ -18,10 +19,12 @@ const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR can only call other
 const unsafe fn foo2() -> u32 { 42 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
 const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR can only call other `const fn`
 
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // conformity is required, even with `const_fn` feature gate
 const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` op
 
@@ -30,6 +33,7 @@ const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool
 const unsafe fn foo2_gated() -> u32 { 42 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
 const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } }
 //~^ ERROR can only call other `const fn`
diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr
index bc6f8c59606..ae92602d45f 100644
--- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr
@@ -1,5 +1,5 @@
 error[E0723]: can only call other `const fn` within a `const fn`, but `const foo` is not stable as `const fn`
-  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:15:41
+  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:16:41
    |
 LL | const unsafe fn bar() -> u32 { unsafe { foo() } }
    |                                         ^^^^^
@@ -8,7 +8,7 @@ LL | const unsafe fn bar() -> u32 { unsafe { foo() } }
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2` is not stable as `const fn`
-  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:22:42
+  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:24:42
    |
 LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } }
    |                                          ^^^^^^
@@ -17,7 +17,7 @@ LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } }
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: only int, `bool` and `char` operations are stable in const fn
-  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:26:33
+  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:29:33
    |
 LL | const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 }
    |                                 ^^^^^^^^^^^^^
@@ -26,7 +26,7 @@ LL | const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 }
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2_gated` is not stable as `const fn`
-  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:34:48
+  --> $DIR/min_const_unsafe_fn_libstd_stability.rs:38:48
    |
 LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } }
    |                                                ^^^^^^^^^^^^
diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs
index deb2cb6b619..121177f8366 100644
--- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs
+++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs
@@ -3,14 +3,15 @@
             we're apparently really bad at it",
             issue = "0")]
 
-#![feature(rustc_const_unstable, const_fn, foo, foo2)]
+#![feature(const_fn, foo, foo2)]
 #![feature(staged_api)]
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature="foo")]
+#[rustc_const_unstable(feature="foo", issue = "0")]
 const fn foo() -> u32 { 42 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
 const unsafe fn bar() -> u32 { foo() } //~ ERROR can only call other `const fn`
 
@@ -18,6 +19,7 @@ const unsafe fn bar() -> u32 { foo() } //~ ERROR can only call other `const fn`
 const fn foo2() -> u32 { 42 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
 const unsafe fn bar2() -> u32 { foo2() } //~ ERROR can only call other `const fn`
 
@@ -26,6 +28,7 @@ const unsafe fn bar2() -> u32 { foo2() } //~ ERROR can only call other `const fn
 const fn foo2_gated() -> u32 { 42 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 // can't call non-min_const_fn
 const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `const fn`
 
diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr
index a14fd740c67..a0db74cfad6 100644
--- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr
+++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr
@@ -1,5 +1,5 @@
 error[E0723]: can only call other `const fn` within a `const fn`, but `const foo` is not stable as `const fn`
-  --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:15:32
+  --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:16:32
    |
 LL | const unsafe fn bar() -> u32 { foo() }
    |                                ^^^^^
@@ -8,7 +8,7 @@ LL | const unsafe fn bar() -> u32 { foo() }
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2` is not stable as `const fn`
-  --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:22:33
+  --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:24:33
    |
 LL | const unsafe fn bar2() -> u32 { foo2() }
    |                                 ^^^^^^
@@ -17,7 +17,7 @@ LL | const unsafe fn bar2() -> u32 { foo2() }
    = help: add `#![feature(const_fn)]` to the crate attributes to enable
 
 error[E0723]: can only call other `const fn` within a `const fn`, but `const foo2_gated` is not stable as `const fn`
-  --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:30:39
+  --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:33:39
    |
 LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() }
    |                                       ^^^^^^^^^^^^
diff --git a/src/test/ui/consts/unstable-const-fn-in-libcore.rs b/src/test/ui/consts/unstable-const-fn-in-libcore.rs
index cad1516fc78..655ad7b548a 100644
--- a/src/test/ui/consts/unstable-const-fn-in-libcore.rs
+++ b/src/test/ui/consts/unstable-const-fn-in-libcore.rs
@@ -14,7 +14,7 @@ enum Opt<T> {
 }
 
 impl<T> Opt<T> {
-    #[rustc_const_unstable(feature = "foo")]
+    #[rustc_const_unstable(feature = "foo", issue = "0")]
     #[stable(feature = "rust1", since = "1.0.0")]
     const fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
     //~^ ERROR destructors cannot be evaluated at compile-time
diff --git a/src/test/ui/feature-gate/allow-features-empty.rs b/src/test/ui/feature-gate/allow-features-empty.rs
index 641e4b852e7..88a60934927 100644
--- a/src/test/ui/feature-gate/allow-features-empty.rs
+++ b/src/test/ui/feature-gate/allow-features-empty.rs
@@ -1,8 +1,6 @@
 // compile-flags: -Z allow_features=
 // Note: This test uses rustc internal flags because they will never stabilize.
 
-#![feature(rustc_const_unstable)] //~ ERROR
-
 #![feature(lang_items)] //~ ERROR
 
 #![feature(unknown_stdlib_feature)] //~ ERROR
diff --git a/src/test/ui/feature-gate/allow-features-empty.stderr b/src/test/ui/feature-gate/allow-features-empty.stderr
index a87d1058503..f88b3ea0a60 100644
--- a/src/test/ui/feature-gate/allow-features-empty.stderr
+++ b/src/test/ui/feature-gate/allow-features-empty.stderr
@@ -1,21 +1,15 @@
-error[E0725]: the feature `rustc_const_unstable` is not in the list of allowed features
-  --> $DIR/allow-features-empty.rs:4:12
-   |
-LL | #![feature(rustc_const_unstable)]
-   |            ^^^^^^^^^^^^^^^^^^^^
-
 error[E0725]: the feature `lang_items` is not in the list of allowed features
-  --> $DIR/allow-features-empty.rs:6:12
+  --> $DIR/allow-features-empty.rs:4:12
    |
 LL | #![feature(lang_items)]
    |            ^^^^^^^^^^
 
 error[E0725]: the feature `unknown_stdlib_feature` is not in the list of allowed features
-  --> $DIR/allow-features-empty.rs:8:12
+  --> $DIR/allow-features-empty.rs:6:12
    |
 LL | #![feature(unknown_stdlib_feature)]
    |            ^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0725`.
diff --git a/src/test/ui/feature-gate/allow-features.rs b/src/test/ui/feature-gate/allow-features.rs
index de69e48a65f..2ce4701a818 100644
--- a/src/test/ui/feature-gate/allow-features.rs
+++ b/src/test/ui/feature-gate/allow-features.rs
@@ -1,8 +1,6 @@
 // compile-flags: -Z allow_features=lang_items
 // Note: This test uses rustc internal flags because they will never stabilize.
 
-#![feature(rustc_const_unstable)] //~ ERROR
-
 #![feature(lang_items)]
 
 #![feature(unknown_stdlib_feature)] //~ ERROR
diff --git a/src/test/ui/feature-gate/allow-features.stderr b/src/test/ui/feature-gate/allow-features.stderr
index 157dddf06ad..9caf48dd138 100644
--- a/src/test/ui/feature-gate/allow-features.stderr
+++ b/src/test/ui/feature-gate/allow-features.stderr
@@ -1,15 +1,9 @@
-error[E0725]: the feature `rustc_const_unstable` is not in the list of allowed features
-  --> $DIR/allow-features.rs:4:12
-   |
-LL | #![feature(rustc_const_unstable)]
-   |            ^^^^^^^^^^^^^^^^^^^^
-
 error[E0725]: the feature `unknown_stdlib_feature` is not in the list of allowed features
-  --> $DIR/allow-features.rs:8:12
+  --> $DIR/allow-features.rs:6:12
    |
 LL | #![feature(unknown_stdlib_feature)]
    |            ^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0725`.
diff --git a/src/test/ui/feature-gates/feature-gate-rustc_const_unstable.rs b/src/test/ui/feature-gates/feature-gate-rustc_const_unstable.rs
index 6961e68744f..3296a17a0b7 100644
--- a/src/test/ui/feature-gates/feature-gate-rustc_const_unstable.rs
+++ b/src/test/ui/feature-gates/feature-gate-rustc_const_unstable.rs
@@ -1,11 +1,8 @@
 // Test internal const fn feature gate.
 
-#![feature(staged_api)]
 #![feature(const_fn)]
-//#![feature(rustc_const_unstable)]
 
-#[stable(feature="zing", since="1.0.0")]
-#[rustc_const_unstable(feature="fzzzzzt")] //~ERROR internal feature
+#[rustc_const_unstable(feature="fzzzzzt")] //~ stability attributes may not be used outside
 pub const fn bazinga() {}
 
 fn main() {
diff --git a/src/test/ui/feature-gates/feature-gate-rustc_const_unstable.stderr b/src/test/ui/feature-gates/feature-gate-rustc_const_unstable.stderr
index d7b7cf72a26..9df926dcf90 100644
--- a/src/test/ui/feature-gates/feature-gate-rustc_const_unstable.stderr
+++ b/src/test/ui/feature-gates/feature-gate-rustc_const_unstable.stderr
@@ -1,11 +1,9 @@
-error[E0658]: the `#[rustc_const_unstable]` attribute is an internal feature
-  --> $DIR/feature-gate-rustc_const_unstable.rs:8:1
+error[E0734]: stability attributes may not be used outside of the standard library
+  --> $DIR/feature-gate-rustc_const_unstable.rs:5:1
    |
 LL | #[rustc_const_unstable(feature="fzzzzzt")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: add `#![feature(rustc_const_unstable)]` to the crate attributes to enable
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0658`.
+For more information about this error, try `rustc --explain E0734`.
diff --git a/src/test/ui/invalid_const_promotion.rs b/src/test/ui/invalid_const_promotion.rs
index 91115ef74b8..5d7664cefb3 100644
--- a/src/test/ui/invalid_const_promotion.rs
+++ b/src/test/ui/invalid_const_promotion.rs
@@ -22,6 +22,7 @@ use std::process::{Command, Stdio};
 // of the const fn kicks in, causing a different code path in the
 // compiler to be executed (see PR #66294).
 #[stable(feature = "rustc", since = "1.0.0")]
+#[rustc_const_stable(feature = "rustc", since = "1.0.0")]
 #[rustc_promotable]
 const fn bar(_: bool) -> usize { 0 - 1 }
 
diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity.rs b/src/test/ui/stability-attribute/stability-attribute-sanity.rs
index 38421e2e6ef..2e3d790d2d8 100644
--- a/src/test/ui/stability-attribute/stability-attribute-sanity.rs
+++ b/src/test/ui/stability-attribute/stability-attribute-sanity.rs
@@ -1,6 +1,6 @@
 // Various checks that stability attributes are used correctly, per RFC 507
 
-#![feature(const_fn, staged_api, rustc_const_unstable)]
+#![feature(const_fn, staged_api)]
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
@@ -60,11 +60,10 @@ fn multiple3() { }
 #[stable(feature = "a", since = "b")]
 #[rustc_deprecated(since = "b", reason = "text")]
 #[rustc_deprecated(since = "b", reason = "text")]
-#[rustc_const_unstable(feature = "c")]
-#[rustc_const_unstable(feature = "d")]
+#[rustc_const_unstable(feature = "c", issue = "0")]
+#[rustc_const_unstable(feature = "d", issue = "0")] //~ ERROR multiple stability levels
 pub const fn multiple4() { } //~ ERROR multiple rustc_deprecated attributes [E0540]
 //~^ ERROR Invalid stability or deprecation version found
-//~| ERROR multiple rustc_const_unstable attributes
 
 #[rustc_deprecated(since = "a", reason = "text")]
 fn deprecated_without_unstable_or_stable() { }
diff --git a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr
index 4b7ec821f45..552e078f45f 100644
--- a/src/test/ui/stability-attribute/stability-attribute-sanity.stderr
+++ b/src/test/ui/stability-attribute/stability-attribute-sanity.stderr
@@ -88,11 +88,11 @@ error[E0540]: multiple rustc_deprecated attributes
 LL | pub const fn multiple4() { }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0553]: multiple rustc_const_unstable attributes
-  --> $DIR/stability-attribute-sanity.rs:65:1
+error[E0544]: multiple stability levels
+  --> $DIR/stability-attribute-sanity.rs:64:1
    |
-LL | pub const fn multiple4() { }
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_const_unstable(feature = "d", issue = "0")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: Invalid stability or deprecation version found
   --> $DIR/stability-attribute-sanity.rs:65:1
@@ -101,7 +101,7 @@ LL | pub const fn multiple4() { }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0549]: rustc_deprecated attribute must be paired with either stable or unstable attribute
-  --> $DIR/stability-attribute-sanity.rs:70:1
+  --> $DIR/stability-attribute-sanity.rs:69:1
    |
 LL | fn deprecated_without_unstable_or_stable() { }
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs
index 41c4b618e60..22e4111ff3a 100644
--- a/src/tools/tidy/src/error_codes_check.rs
+++ b/src/tools/tidy/src/error_codes_check.rs
@@ -41,6 +41,7 @@ const WHITELIST: &[&str] = &[
     "E0514",
     "E0519",
     "E0523",
+    "E0553",
     "E0554",
     "E0570",
     "E0629",