diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index 148193b5a97..d0ce209be44 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -1,6 +1,6 @@
-#![cfg_attr(all(doc, not(bootstrap)), allow(internal_features))]
-#![cfg_attr(all(doc, not(bootstrap)), feature(rustdoc_internals))]
-#![cfg_attr(all(doc, not(bootstrap)), doc(rust_logo))]
+#![cfg_attr(doc, allow(internal_features))]
+#![cfg_attr(doc, feature(rustdoc_internals))]
+#![cfg_attr(doc, doc(rust_logo))]
 #![feature(rustc_private)]
 // Note: please avoid adding other feature gates where possible
 #![warn(rust_2018_idioms)]
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 3c42eb21d07..a81056ed3ad 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -8,7 +8,6 @@
 #![feature(rustdoc_internals)]
 #![doc(rust_logo)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
-#![cfg_attr(bootstrap, feature(c_str_literals))]
 #![feature(exact_size_is_empty)]
 #![feature(extern_types)]
 #![feature(hash_raw_entry)]
diff --git a/compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs b/compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs
index cafa91c8b8b..f17a0bf26d7 100644
--- a/compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs
+++ b/compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs
@@ -81,150 +81,6 @@
 ///     E::A,
 /// }
 /// ```
-#[cfg(bootstrap)]
-#[macro_export]
-macro_rules! impl_tag {
-    (
-        impl Tag for $Self:ty;
-        $(
-            $($path:ident)::* $( { $( $fields:tt )* })?,
-        )*
-    ) => {
-        // Safety:
-        // `bits_for_tags` is called on the same `${index()}`-es as
-        // `into_usize` returns, thus `BITS` constant is correct.
-        unsafe impl $crate::tagged_ptr::Tag for $Self {
-            const BITS: u32 = $crate::tagged_ptr::bits_for_tags(&[
-                $(
-                    ${index()},
-                    $( ${ignore(path)} )*
-                )*
-            ]);
-
-            #[inline]
-            fn into_usize(self) -> usize {
-                // This forbids use of repeating patterns (`Enum::V`&`Enum::V`, etc)
-                // (or at least it should, see <https://github.com/rust-lang/rust/issues/110613>)
-                #[forbid(unreachable_patterns)]
-                match self {
-                    // `match` is doing heavy lifting here, by requiring exhaustiveness
-                    $(
-                        $($path)::* $( { $( $fields )* } )? => ${index()},
-                    )*
-                }
-            }
-
-            #[inline]
-            unsafe fn from_usize(tag: usize) -> Self {
-                match tag {
-                    $(
-                        ${index()} => $($path)::* $( { $( $fields )* } )?,
-                    )*
-
-                    // Safety:
-                    // `into_usize` only returns `${index()}` of the same
-                    // repetition as we are filtering above, thus if this is
-                    // reached, the safety contract of this function was
-                    // already breached.
-                    _ => unsafe {
-                        debug_assert!(
-                            false,
-                            "invalid tag: {tag}\
-                             (this is a bug in the caller of `from_usize`)"
-                        );
-                        std::hint::unreachable_unchecked()
-                    },
-                }
-            }
-
-        }
-    };
-}
-
-/// Implements [`Tag`] for a given type.
-///
-/// You can use `impl_tag` on structs and enums.
-/// You need to specify the type and all its possible values,
-/// which can only be paths with optional fields.
-///
-/// [`Tag`]: crate::tagged_ptr::Tag
-///
-/// # Examples
-///
-/// Basic usage:
-///
-/// ```
-/// #![feature(macro_metavar_expr)]
-/// use rustc_data_structures::{impl_tag, tagged_ptr::Tag};
-///
-/// #[derive(Copy, Clone, PartialEq, Debug)]
-/// enum SomeTag {
-///     A,
-///     B,
-///     X { v: bool },
-///     Y(bool, bool),
-/// }
-///
-/// impl_tag! {
-///     // The type for which the `Tag` will be implemented
-///     impl Tag for SomeTag;
-///     // You need to specify all possible tag values:
-///     SomeTag::A, // 0
-///     SomeTag::B, // 1
-///     // For variants with fields, you need to specify the fields:
-///     SomeTag::X { v: true  }, // 2
-///     SomeTag::X { v: false }, // 3
-///     // For tuple variants use named syntax:
-///     SomeTag::Y { 0: true,  1: true  }, // 4
-///     SomeTag::Y { 0: false, 1: true  }, // 5
-///     SomeTag::Y { 0: true,  1: false }, // 6
-///     SomeTag::Y { 0: false, 1: false }, // 7
-/// }
-///
-/// // Tag values are assigned in order:
-/// assert_eq!(SomeTag::A.into_usize(), 0);
-/// assert_eq!(SomeTag::X { v: false }.into_usize(), 3);
-/// assert_eq!(SomeTag::Y(false, true).into_usize(), 5);
-///
-/// assert_eq!(unsafe { SomeTag::from_usize(1) }, SomeTag::B);
-/// assert_eq!(unsafe { SomeTag::from_usize(2) }, SomeTag::X { v: true });
-/// assert_eq!(unsafe { SomeTag::from_usize(7) }, SomeTag::Y(false, false));
-/// ```
-///
-/// Structs are supported:
-///
-/// ```
-/// #![feature(macro_metavar_expr)]
-/// # use rustc_data_structures::impl_tag;
-/// #[derive(Copy, Clone)]
-/// struct Flags { a: bool, b: bool }
-///
-/// impl_tag! {
-///     impl Tag for Flags;
-///     Flags { a: true,  b: true  },
-///     Flags { a: false, b: true  },
-///     Flags { a: true,  b: false },
-///     Flags { a: false, b: false },
-/// }
-/// ```
-///
-/// Not specifying all values results in a compile error:
-///
-/// ```compile_fail,E0004
-/// #![feature(macro_metavar_expr)]
-/// # use rustc_data_structures::impl_tag;
-/// #[derive(Copy, Clone)]
-/// enum E {
-///     A,
-///     B,
-/// }
-///
-/// impl_tag! {
-///     impl Tag for E;
-///     E::A,
-/// }
-/// ```
-#[cfg(not(bootstrap))]
 #[macro_export]
 macro_rules! impl_tag {
     (
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 89caf8aa231..da727ddb208 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -41,132 +41,6 @@ use std::path::PathBuf;
 use std::rc::Rc;
 use std::{iter, mem};
 
-#[cfg(bootstrap)]
-macro_rules! ast_fragments {
-    (
-        $($Kind:ident($AstTy:ty) {
-            $kind_name:expr;
-            $(one fn $mut_visit_ast:ident; fn $visit_ast:ident;)?
-            $(many fn $flat_map_ast_elt:ident; fn $visit_ast_elt:ident($($args:tt)*);)?
-            fn $make_ast:ident;
-        })*
-    ) => {
-        /// A fragment of AST that can be produced by a single macro expansion.
-        /// Can also serve as an input and intermediate result for macro expansion operations.
-        pub enum AstFragment {
-            OptExpr(Option<P<ast::Expr>>),
-            MethodReceiverExpr(P<ast::Expr>),
-            $($Kind($AstTy),)*
-        }
-
-        /// "Discriminant" of an AST fragment.
-        #[derive(Copy, Clone, PartialEq, Eq)]
-        pub enum AstFragmentKind {
-            OptExpr,
-            MethodReceiverExpr,
-            $($Kind,)*
-        }
-
-        impl AstFragmentKind {
-            pub fn name(self) -> &'static str {
-                match self {
-                    AstFragmentKind::OptExpr => "expression",
-                    AstFragmentKind::MethodReceiverExpr => "expression",
-                    $(AstFragmentKind::$Kind => $kind_name,)*
-                }
-            }
-
-            fn make_from<'a>(self, result: Box<dyn MacResult + 'a>) -> Option<AstFragment> {
-                match self {
-                    AstFragmentKind::OptExpr =>
-                        result.make_expr().map(Some).map(AstFragment::OptExpr),
-                    AstFragmentKind::MethodReceiverExpr =>
-                        result.make_expr().map(AstFragment::MethodReceiverExpr),
-                    $(AstFragmentKind::$Kind => result.$make_ast().map(AstFragment::$Kind),)*
-                }
-            }
-        }
-
-        impl AstFragment {
-            pub fn add_placeholders(&mut self, placeholders: &[NodeId]) {
-                if placeholders.is_empty() {
-                    return;
-                }
-                match self {
-                    $($(AstFragment::$Kind(ast) => ast.extend(placeholders.iter().flat_map(|id| {
-                        ${ignore(flat_map_ast_elt)}
-                        placeholder(AstFragmentKind::$Kind, *id, None).$make_ast()
-                    })),)?)*
-                    _ => panic!("unexpected AST fragment kind")
-                }
-            }
-
-            pub fn make_opt_expr(self) -> Option<P<ast::Expr>> {
-                match self {
-                    AstFragment::OptExpr(expr) => expr,
-                    _ => panic!("AstFragment::make_* called on the wrong kind of fragment"),
-                }
-            }
-
-            pub fn make_method_receiver_expr(self) -> P<ast::Expr> {
-                match self {
-                    AstFragment::MethodReceiverExpr(expr) => expr,
-                    _ => panic!("AstFragment::make_* called on the wrong kind of fragment"),
-                }
-            }
-
-            $(pub fn $make_ast(self) -> $AstTy {
-                match self {
-                    AstFragment::$Kind(ast) => ast,
-                    _ => panic!("AstFragment::make_* called on the wrong kind of fragment"),
-                }
-            })*
-
-            fn make_ast<T: InvocationCollectorNode>(self) -> T::OutputTy {
-                T::fragment_to_output(self)
-            }
-
-            pub fn mut_visit_with<F: MutVisitor>(&mut self, vis: &mut F) {
-                match self {
-                    AstFragment::OptExpr(opt_expr) => {
-                        visit_clobber(opt_expr, |opt_expr| {
-                            if let Some(expr) = opt_expr {
-                                vis.filter_map_expr(expr)
-                            } else {
-                                None
-                            }
-                        });
-                    }
-                    AstFragment::MethodReceiverExpr(expr) => vis.visit_method_receiver_expr(expr),
-                    $($(AstFragment::$Kind(ast) => vis.$mut_visit_ast(ast),)?)*
-                    $($(AstFragment::$Kind(ast) =>
-                        ast.flat_map_in_place(|ast| vis.$flat_map_ast_elt(ast)),)?)*
-                }
-            }
-
-            pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) {
-                match self {
-                    AstFragment::OptExpr(Some(expr)) => visitor.visit_expr(expr),
-                    AstFragment::OptExpr(None) => {}
-                    AstFragment::MethodReceiverExpr(expr) => visitor.visit_method_receiver_expr(expr),
-                    $($(AstFragment::$Kind(ast) => visitor.$visit_ast(ast),)?)*
-                    $($(AstFragment::$Kind(ast) => for ast_elt in &ast[..] {
-                        visitor.$visit_ast_elt(ast_elt, $($args)*);
-                    })?)*
-                }
-            }
-        }
-
-        impl<'a> MacResult for crate::mbe::macro_rules::ParserAnyMacro<'a> {
-            $(fn $make_ast(self: Box<crate::mbe::macro_rules::ParserAnyMacro<'a>>)
-                           -> Option<$AstTy> {
-                Some(self.make(AstFragmentKind::$Kind).$make_ast())
-            })*
-        }
-    }
-}
-
-#[cfg(not(bootstrap))]
 macro_rules! ast_fragments {
     (
         $($Kind:ident($AstTy:ty) {
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index a4ab5527e3f..0fc24e88b3b 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -39,7 +39,6 @@
 #![feature(min_specialization)]
 #![feature(never_type)]
 #![feature(rustc_attrs)]
-#![cfg_attr(bootstrap, feature(trait_upcasting))]
 #![recursion_limit = "256"]
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index e048268fad1..3475e582a8f 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -49,7 +49,6 @@
 #![feature(associated_type_bounds)]
 #![feature(rustc_attrs)]
 #![feature(control_flow_enum)]
-#![cfg_attr(bootstrap, feature(trait_upcasting))]
 #![feature(trusted_step)]
 #![feature(try_blocks)]
 #![feature(try_reserve_kind)]
diff --git a/library/core/src/async_iter/async_iter.rs b/library/core/src/async_iter/async_iter.rs
index 8a45bd36f7a..a8197332fd0 100644
--- a/library/core/src/async_iter/async_iter.rs
+++ b/library/core/src/async_iter/async_iter.rs
@@ -13,7 +13,7 @@ use crate::task::{Context, Poll};
 #[unstable(feature = "async_iterator", issue = "79024")]
 #[must_use = "async iterators do nothing unless polled"]
 #[doc(alias = "Stream")]
-#[cfg_attr(not(bootstrap), lang = "async_iterator")]
+#[lang = "async_iterator"]
 pub trait AsyncIterator {
     /// The type of items yielded by the async iterator.
     type Item;
@@ -116,7 +116,7 @@ impl<T> Poll<Option<T>> {
     /// A helper function for internal desugaring -- produces `Ready(Some(t))`,
     /// which corresponds to the async iterator yielding a value.
     #[unstable(feature = "async_gen_internals", issue = "none")]
-    #[cfg_attr(not(bootstrap), lang = "AsyncGenReady")]
+    #[lang = "AsyncGenReady"]
     pub fn async_gen_ready(t: T) -> Self {
         Poll::Ready(Some(t))
     }
@@ -124,13 +124,13 @@ impl<T> Poll<Option<T>> {
     /// A helper constant for internal desugaring -- produces `Pending`,
     /// which corresponds to the async iterator pending on an `.await`.
     #[unstable(feature = "async_gen_internals", issue = "none")]
-    #[cfg_attr(not(bootstrap), lang = "AsyncGenPending")]
+    #[lang = "AsyncGenPending"]
     // FIXME(gen_blocks): This probably could be deduplicated.
     pub const PENDING: Self = Poll::Pending;
 
     /// A helper constant for internal desugaring -- produces `Ready(None)`,
     /// which corresponds to the async iterator finishing its iteration.
     #[unstable(feature = "async_gen_internals", issue = "none")]
-    #[cfg_attr(not(bootstrap), lang = "AsyncGenFinished")]
+    #[lang = "AsyncGenFinished"]
     pub const FINISHED: Self = Poll::Ready(None);
 }
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index d7c41ac5c06..bffd3b2af97 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -224,13 +224,13 @@ use self::Ordering::*;
     append_const_msg
 )]
 #[rustc_diagnostic_item = "PartialEq"]
-#[cfg_attr(not(bootstrap), const_trait)]
+#[const_trait]
 pub trait PartialEq<Rhs: ?Sized = Self> {
     /// This method tests for `self` and `other` values to be equal, and is used
     /// by `==`.
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[cfg_attr(not(bootstrap), rustc_diagnostic_item = "cmp_partialeq_eq")]
+    #[rustc_diagnostic_item = "cmp_partialeq_eq"]
     fn eq(&self, other: &Rhs) -> bool;
 
     /// This method tests for `!=`. The default implementation is almost always
@@ -238,7 +238,7 @@ pub trait PartialEq<Rhs: ?Sized = Self> {
     #[inline]
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
-    #[cfg_attr(not(bootstrap), rustc_diagnostic_item = "cmp_partialeq_ne")]
+    #[rustc_diagnostic_item = "cmp_partialeq_ne"]
     fn ne(&self, other: &Rhs) -> bool {
         !self.eq(other)
     }
@@ -1416,18 +1416,8 @@ mod impls {
 
     macro_rules! partial_eq_impl {
         ($($t:ty)*) => ($(
-            #[stable(feature = "rust1", since = "1.0.0")]
-            #[cfg(bootstrap)]
-            impl PartialEq for $t {
-                #[inline]
-                fn eq(&self, other: &$t) -> bool { (*self) == (*other) }
-                #[inline]
-                fn ne(&self, other: &$t) -> bool { (*self) != (*other) }
-            }
-
             #[stable(feature = "rust1", since = "1.0.0")]
             #[rustc_const_unstable(feature = "const_cmp", issue = "92391")]
-            #[cfg(not(bootstrap))]
             impl const PartialEq for $t {
                 #[inline]
                 fn eq(&self, other: &$t) -> bool { (*self) == (*other) }
diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs
index 68c8a335b40..0fd27974dce 100644
--- a/library/core/src/intrinsics/simd.rs
+++ b/library/core/src/intrinsics/simd.rs
@@ -257,7 +257,6 @@ extern "platform-intrinsic" {
     /// type).
     ///
     /// `mask` must only contain `0` or `!0` values.
-    #[cfg(not(bootstrap))]
     pub fn simd_masked_load<V, U, T>(mask: V, ptr: U, val: T) -> T;
 
     /// Write to a vector of pointers.
@@ -277,7 +276,6 @@ extern "platform-intrinsic" {
     /// type).
     ///
     /// `mask` must only contain `0` or `!0` values.
-    #[cfg(not(bootstrap))]
     pub fn simd_masked_store<V, U, T>(mask: V, ptr: U, val: T);
 
     /// Add two simd vectors elementwise, with saturation.
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index a444c30c756..12ff64de879 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -1772,7 +1772,7 @@ impl<T> *const [T] {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized> PartialEq for *const T {
     #[inline]
-    #[cfg_attr(not(bootstrap), allow(ambiguous_wide_pointer_comparisons))]
+    #[allow(ambiguous_wide_pointer_comparisons)]
     fn eq(&self, other: &*const T) -> bool {
         *self == *other
     }
@@ -1785,7 +1785,7 @@ impl<T: ?Sized> Eq for *const T {}
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized> Ord for *const T {
     #[inline]
-    #[cfg_attr(not(bootstrap), allow(ambiguous_wide_pointer_comparisons))]
+    #[allow(ambiguous_wide_pointer_comparisons)]
     fn cmp(&self, other: &*const T) -> Ordering {
         if self < other {
             Less
@@ -1805,25 +1805,25 @@ impl<T: ?Sized> PartialOrd for *const T {
     }
 
     #[inline]
-    #[cfg_attr(not(bootstrap), allow(ambiguous_wide_pointer_comparisons))]
+    #[allow(ambiguous_wide_pointer_comparisons)]
     fn lt(&self, other: &*const T) -> bool {
         *self < *other
     }
 
     #[inline]
-    #[cfg_attr(not(bootstrap), allow(ambiguous_wide_pointer_comparisons))]
+    #[allow(ambiguous_wide_pointer_comparisons)]
     fn le(&self, other: &*const T) -> bool {
         *self <= *other
     }
 
     #[inline]
-    #[cfg_attr(not(bootstrap), allow(ambiguous_wide_pointer_comparisons))]
+    #[allow(ambiguous_wide_pointer_comparisons)]
     fn gt(&self, other: &*const T) -> bool {
         *self > *other
     }
 
     #[inline]
-    #[cfg_attr(not(bootstrap), allow(ambiguous_wide_pointer_comparisons))]
+    #[allow(ambiguous_wide_pointer_comparisons)]
     fn ge(&self, other: &*const T) -> bool {
         *self >= *other
     }
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 390e0737197..a9078854125 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -1900,7 +1900,7 @@ pub(crate) const unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usiz
 #[inline(always)]
 #[must_use = "pointer comparison produces a value"]
 #[rustc_diagnostic_item = "ptr_eq"]
-#[cfg_attr(not(bootstrap), allow(ambiguous_wide_pointer_comparisons))] // it's actually clear here
+#[allow(ambiguous_wide_pointer_comparisons)] // it's actually clear here
 pub fn eq<T: ?Sized>(a: *const T, b: *const T) -> bool {
     a == b
 }
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 9e7b8ec64ac..4f5fca4367d 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -2199,7 +2199,7 @@ impl<T> *mut [T] {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized> PartialEq for *mut T {
     #[inline(always)]
-    #[cfg_attr(not(bootstrap), allow(ambiguous_wide_pointer_comparisons))]
+    #[allow(ambiguous_wide_pointer_comparisons)]
     fn eq(&self, other: &*mut T) -> bool {
         *self == *other
     }
@@ -2211,7 +2211,7 @@ impl<T: ?Sized> Eq for *mut T {}
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized> Ord for *mut T {
     #[inline]
-    #[cfg_attr(not(bootstrap), allow(ambiguous_wide_pointer_comparisons))]
+    #[allow(ambiguous_wide_pointer_comparisons)]
     fn cmp(&self, other: &*mut T) -> Ordering {
         if self < other {
             Less
@@ -2231,25 +2231,25 @@ impl<T: ?Sized> PartialOrd for *mut T {
     }
 
     #[inline(always)]
-    #[cfg_attr(not(bootstrap), allow(ambiguous_wide_pointer_comparisons))]
+    #[allow(ambiguous_wide_pointer_comparisons)]
     fn lt(&self, other: &*mut T) -> bool {
         *self < *other
     }
 
     #[inline(always)]
-    #[cfg_attr(not(bootstrap), allow(ambiguous_wide_pointer_comparisons))]
+    #[allow(ambiguous_wide_pointer_comparisons)]
     fn le(&self, other: &*mut T) -> bool {
         *self <= *other
     }
 
     #[inline(always)]
-    #[cfg_attr(not(bootstrap), allow(ambiguous_wide_pointer_comparisons))]
+    #[allow(ambiguous_wide_pointer_comparisons)]
     fn gt(&self, other: &*mut T) -> bool {
         *self > *other
     }
 
     #[inline(always)]
-    #[cfg_attr(not(bootstrap), allow(ambiguous_wide_pointer_comparisons))]
+    #[allow(ambiguous_wide_pointer_comparisons)]
     fn ge(&self, other: &*mut T) -> bool {
         *self >= *other
     }
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index 77961506e13..427a9f3f494 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -1791,7 +1791,7 @@ impl<T: ?Sized> Eq for NonNull<T> {}
 #[stable(feature = "nonnull", since = "1.25.0")]
 impl<T: ?Sized> PartialEq for NonNull<T> {
     #[inline]
-    #[cfg_attr(not(bootstrap), allow(ambiguous_wide_pointer_comparisons))]
+    #[allow(ambiguous_wide_pointer_comparisons)]
     fn eq(&self, other: &Self) -> bool {
         self.as_ptr() == other.as_ptr()
     }
diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs
index 3689312e6ae..e1b77e34f21 100644
--- a/library/core/src/tuple.rs
+++ b/library/core/src/tuple.rs
@@ -8,146 +8,6 @@ use crate::marker::{StructuralEq, StructuralPartialEq};
 //
 // Also provides implementations for tuples with lesser arity. For example, tuple_impls!(A B C)
 // will implement everything for (A, B, C), (A, B) and (A,).
-#[cfg(bootstrap)]
-macro_rules! tuple_impls {
-    // Stopping criteria (1-ary tuple)
-    ($T:ident) => {
-        tuple_impls!(@impl $T);
-    };
-    // Running criteria (n-ary tuple, with n >= 2)
-    ($T:ident $( $U:ident )+) => {
-        tuple_impls!($( $U )+);
-        tuple_impls!(@impl $T $( $U )+);
-    };
-    // "Private" internal implementation
-    (@impl $( $T:ident )+) => {
-        maybe_tuple_doc! {
-            $($T)+ @
-            #[stable(feature = "rust1", since = "1.0.0")]
-            impl<$($T: PartialEq),+> PartialEq for ($($T,)+)
-            where
-                last_type!($($T,)+): ?Sized
-            {
-                #[inline]
-                fn eq(&self, other: &($($T,)+)) -> bool {
-                    $( ${ignore(T)} self.${index()} == other.${index()} )&&+
-                }
-                #[inline]
-                fn ne(&self, other: &($($T,)+)) -> bool {
-                    $( ${ignore(T)} self.${index()} != other.${index()} )||+
-                }
-            }
-        }
-
-        maybe_tuple_doc! {
-            $($T)+ @
-            #[stable(feature = "rust1", since = "1.0.0")]
-            impl<$($T: Eq),+> Eq for ($($T,)+)
-            where
-                last_type!($($T,)+): ?Sized
-            {}
-        }
-
-        maybe_tuple_doc! {
-            $($T)+ @
-            #[unstable(feature = "structural_match", issue = "31434")]
-            impl<$($T: ConstParamTy),+> ConstParamTy for ($($T,)+) {}
-        }
-
-        maybe_tuple_doc! {
-            $($T)+ @
-            #[unstable(feature = "structural_match", issue = "31434")]
-            impl<$($T),+> StructuralPartialEq for ($($T,)+) {}
-        }
-
-        maybe_tuple_doc! {
-            $($T)+ @
-            #[unstable(feature = "structural_match", issue = "31434")]
-            impl<$($T),+> StructuralEq for ($($T,)+) {}
-        }
-
-        maybe_tuple_doc! {
-            $($T)+ @
-            #[stable(feature = "rust1", since = "1.0.0")]
-            impl<$($T: PartialOrd),+> PartialOrd for ($($T,)+)
-            where
-                last_type!($($T,)+): ?Sized
-            {
-                #[inline]
-                fn partial_cmp(&self, other: &($($T,)+)) -> Option<Ordering> {
-                    lexical_partial_cmp!($( ${ignore(T)} self.${index()}, other.${index()} ),+)
-                }
-                #[inline]
-                fn lt(&self, other: &($($T,)+)) -> bool {
-                    lexical_ord!(lt, Less, $( ${ignore(T)} self.${index()}, other.${index()} ),+)
-                }
-                #[inline]
-                fn le(&self, other: &($($T,)+)) -> bool {
-                    lexical_ord!(le, Less, $( ${ignore(T)} self.${index()}, other.${index()} ),+)
-                }
-                #[inline]
-                fn ge(&self, other: &($($T,)+)) -> bool {
-                    lexical_ord!(ge, Greater, $( ${ignore(T)} self.${index()}, other.${index()} ),+)
-                }
-                #[inline]
-                fn gt(&self, other: &($($T,)+)) -> bool {
-                    lexical_ord!(gt, Greater, $( ${ignore(T)} self.${index()}, other.${index()} ),+)
-                }
-            }
-        }
-
-        maybe_tuple_doc! {
-            $($T)+ @
-            #[stable(feature = "rust1", since = "1.0.0")]
-            impl<$($T: Ord),+> Ord for ($($T,)+)
-            where
-                last_type!($($T,)+): ?Sized
-            {
-                #[inline]
-                fn cmp(&self, other: &($($T,)+)) -> Ordering {
-                    lexical_cmp!($( ${ignore(T)} self.${index()}, other.${index()} ),+)
-                }
-            }
-        }
-
-        maybe_tuple_doc! {
-            $($T)+ @
-            #[stable(feature = "rust1", since = "1.0.0")]
-            impl<$($T: Default),+> Default for ($($T,)+) {
-                #[inline]
-                fn default() -> ($($T,)+) {
-                    ($($T::default(),)+)
-                }
-            }
-        }
-
-        #[stable(feature = "array_tuple_conv", since = "1.71.0")]
-        impl<T> From<[T; ${count(T)}]> for ($(${ignore(T)} T,)+) {
-            #[inline]
-            #[allow(non_snake_case)]
-            fn from(array: [T; ${count(T)}]) -> Self {
-                let [$($T,)+] = array;
-                ($($T,)+)
-            }
-        }
-
-        #[stable(feature = "array_tuple_conv", since = "1.71.0")]
-        impl<T> From<($(${ignore(T)} T,)+)> for [T; ${count(T)}] {
-            #[inline]
-            #[allow(non_snake_case)]
-            fn from(tuple: ($(${ignore(T)} T,)+)) -> Self {
-                let ($($T,)+) = tuple;
-                [$($T,)+]
-            }
-        }
-    }
-}
-
-// Recursive macro for implementing n-ary tuple functions and operations
-//
-// Also provides implementations for tuples with lesser arity. For example, tuple_impls!(A B C)
-// will implement everything for (A, B, C), (A, B) and (A,).
-#[cfg(not(bootstrap))]
 macro_rules! tuple_impls {
     // Stopping criteria (1-ary tuple)
     ($T:ident) => {
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index c531117bed5..fabdd4ee25d 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -111,7 +111,6 @@
 #![feature(slice_flatten)]
 #![feature(error_generic_member_access)]
 #![feature(error_in_core)]
-#![cfg_attr(bootstrap, feature(trait_upcasting))]
 #![feature(utf8_chunks)]
 #![feature(is_ascii_octdigit)]
 #![feature(get_many_mut)]
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 76081833e05..70b9aab9161 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -308,7 +308,6 @@
 //
 // Library features (core):
 // tidy-alphabetical-start
-#![cfg_attr(bootstrap, feature(c_str_literals))]
 #![feature(char_internals)]
 #![feature(core_intrinsics)]
 #![feature(core_io_borrowed_buf)]
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 1eb40ab826c..4e9febf0205 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -11,7 +11,6 @@
 #![feature(round_ties_even)]
 #![feature(let_chains)]
 #![feature(lint_reasons)]
-#![cfg_attr(bootstrap, feature(trait_upcasting))]
 // Configure clippy and other lints
 #![allow(
     clippy::collapsible_else_if,